지금까지 작성한 TCP 서버-클라이언트의 문제점:
해결책 1: 서버가 각 클라이언트와 통신 시간 줄임
=> 구현이 쉽지만 대용량에 적합하지 않음
해결책 2: 각 클라이언트를 스레드 이용해 독립 처리
=> 소켓 입출력 모델에 비해 구현 쉽지만 서버의 시스템 자원 많이 사용
해결책 3: 소켓 입출력 모델 사용
=> 소수의 스레드 이용해 다수의 클라이언트를 처리하지만 구현 어려움
교착 상태(deadlock): 영원히 일어나지 않을 사건을 두 프로세스가 기다리는 상황
해결책 1: 데이터 송수신 부분 잘 설계
=> 곧바로 구현 가능하지만 모두 해결 불가능
해결책 2: 소켓에 타임아웃 옵션 적용( setsockopt 함수)
=> 구현이 쉽지만 성능 떨어짐
해결책 3: 넌블로킹 소켓 사용
=> 조건 만족하지 않더라도 소켓함수 즉시 리턴해 해결하지만 구현 복잡
해결책 4: 입출력 모델 사용
=> 넌블로킹 단점 보완하며 해결하지만 구현이 어려움
프로그램: 코드, 데이터, 리소스들의 집합
프로세스는 이러한 파일들을 읽어들여 메모리 영역에 담고 있는 컨테이너
스레드란? CPU 시간을 할당 받아 프로세스 메모리 영역에 있는 코드를 수행하고 데이터를 사용하는 실행 흐름
주 스레드(메인 스레드) : 응용 프로그램 실행 시 최초로 생성되는 스레드
main() 함수 또는 WinMain() 함수에서 실행 시작
컨텍스트 전환: 스레드의 실행 상태의 저장과 복원 작업, 교대로 CPU를 사용하지만 지속적인 일을 가능하게 함
CreateThread() 함수: 스레드 생성 후 스레드 핸들을 리턴
HANDLE CreateThread (
LPSECURITY_ATTRIBURES lpThreadAttributes, // 보안 관련 옵션
SIZE_T dwStackSize, // 스레드에 할당되는 스택 크기(바이트 단위 설정(0일 시 디폴크 크기 1M)
LPTHREAD_START_ROUTINE lpStartAddress, // 스레드 함수의 시작 주소, 함수 이름
LPVOID lpParameter, // 스레드 함수에 전달할 인자
DWORD dwCreationFlags,
LPDWORD lpThreadId // 스레드 아이디 리턴
);
스레드 함수의 형태
DWORD WINAPI 스레드함수명(LPVOID lpParameter)
{
...
}
호출 규약
ex. 32비트 윈도우? 표현할 수 있는 범위 = 4GB
void ExitThread(
DWORD dwExitCode // 종료 코드
);
BOOL TerminateThread(
HANDLE hThread, // 종료할 스레드를 가리키는 핸들
DWORD dwExitCode, // 종료 코드
);
BOOL GetExitCodeThread(
HANDLE hThread, // 종료 코드를 확인할 Thread 의 핸들
LPDWORD lpExitCode // 종료 코드를 받아올 변수의 주소 값
);
우선순위 레벨 관련 API 함수
BOOL SetThreadPriority (
HANDLE hThread, // 스레드 핸들
int nPriority // 우선순위 레벨
);
int GetThreadPriority)
HANDLE hThread // 스레드 핸들
);
DWORD WaitForSingleObject (
HANDLE hHandle,
DWORD dwMillieseconds // 타임아웃 설정, INFINITE => 무한대기
);
// 사용 예시
HANDLE hThread = CreateThread(...);
DWORD retval = WaitForSingleObject(hThread, 1000);
if(retval == WAIT_OBJECT_0) { ... } // 스레드 종료
else if(retval == WAIT_TIMEOUT) { ... } // 타임아웃(스레드는 아직 종료 안 함)
else { ... } // 에러 발생
DWORD WaitForMultipleObjects (
DWORD nCount,
const HANDLE* lpHandles,
BOOL bWaitAll, // True=모두 기다림, FALSE= 하나만
DWORD dwMilliseconds
);
// 사용 예시 1: 모든 스레드의 종료를 기다린다
HANDLE hThread[2];
HANDLE hThread[0] = CreateThread(...);
HANDLE hThread[1] = CreateThread(...);
WaitForMultipleObjects(2, hThread, TRUE, INFINITE);
// 사용 예시 2: 스레드 하나의 종료를 기다린다
HANDLE hThread[2];
HANDLE hThread[0] = CreateThread(...);
HANDLE hThread[1] = CreateThread(...);
DWORD retval = WaitForMultipleObjects(2, hThread, FALSE, INFINITE);
switch(retval){
case WAIT_OBJECT_0: // hThread[0] 종료
break;
case WAIT_OBJECT_0 + 1: // hThread[1] 종료
break;
case WAIT_FAILED: // 오류 발생
break;
}
// 실행 일시 중시 함수 1
DWORD SuspendThread (
HANDLE hThread // 스레드 핸들
);
// 재실행 함수
DWORD ResumeThread (
HANDLE hThread // 스레드 핸들
);
// 실행 일시 중지 함수 2
void Sleep(
DWORD dwMilliseconds // 밀리초 (ms)
);
중지 횟수가 관리됨: SuspendThread(): +1, ResumeThread(): -1
빠르게 컨텍스트 전환하기