데이터베이스실험실 석사 2학기 조정희 jjh1977@dblab.hannam.ac.kr TCP/IP Socket Programming… 제 18장 윈도우 기반 쓰레드 사용하기 데이터베이스실험실 석사 2학기 조정희 jjh1977@dblab.hannam.ac.kr
목차 커널 오브젝트 윈도우 기반의 쓰레드 생성 Signaled & Non-Signaled 커널 오브젝트 멀티 쓰레드 프로그래밍의 문제점
커널 오브젝트(Kernel Object) 커널 오브젝트란? 시스템 리소스의 정보를 담고 있는 데이터 블록 파일 관련정보 쓰레드 관련정보 뮤텍스 관련정보 파 일 쓰레드 뮤텍스 시스템 리소스 커널 오브젝트
윈도우 기반의 쓰레드 생성 [1] 쓰레드 생성 #include <windows.h> HANDLE CreateThread( LPSECURITY_ATTRIBUTES lpThreadAttributes, // Security Descriptor SIZE_T dwStackSize, // initial stack size LPTHREAD_START_ROUTINE lpStartAddress, // thread function LPVOID lpParameter, // thread argument DWORD dwCreationFlags, // creation option LPDWORD lpThreadID // thread identifier lpThreadAttributes : 쓰레드의 보안에 관련된 설정을 위한 옵션. 디폴드(Default) 보안 설정을 위해 NULL 포인터를 전달 dwStackSize : 쓰레드 생성 시 요구되는 스택의 크기를 인자로 전달. 0을 전달할 경우 디폴트로 설정되어 있는 스택의 크기를 할당 받음 lpStartAddress : 쓰레드에 의해 호출되는 함수의 포인터를 인자로 전달 lpParameter : lpStartAddress가 가리키는 함수 호출 시, 전달할 인자를 지정 dwCreationFlags : 쓰레드 생성 이후에 바로 실행 가능한 상태냐 대기 상태로 들어가느냐를 결정하는 요소. 0을 전달할 경우 바로 실행 가능한 상태가 됨 lpThreadID : 쓰레드 생성 시 리턴되는 쓰레드의 ID를 저장하기 위한 변수의 포인터
윈도우 기반의 쓰레드 생성 [2] 멀티 쓰레드 기반의 프로그램 작성을 위한 환경 설정 단일 쓰레드 기반 프로그램 멀티 쓰레드 기반의 프로그램 작성을 위한 환경 설정 단일 쓰레드 기반 프로그램 기본적으로 윈도우 기반으로 작성된 프로그램 멀티 쓰레드 기반 프로그램 작성 다중 쓰레드 기반의 프로그램을 위한 Run-Time Library를 링크
윈도우 기반의 쓰레드 생성 [3] Run-Time Library 링크
윈도우 기반의 쓰레드 생성 [4] 쓰레드 안전한 C 라이브러리 함수 사용하기 _beginthreadex #include <pthread.h> unsigned long _beginthreadex( void *security, // Security Descriptor(NULL) unsigned stack_size, // Initial stack size(0) unsigned (*start_address )( void * ), // thread function void *arglist, // thread argument unsigned initflag, // creation option(0) unsigned *thrdaddr // thread identifier ); CreateThread 함수와 전달하는 인자의 수, 인자가 지니는 의미, 순서가 동일 이름과 데이터 타입이 다름
윈도우 기반의 쓰레드 생성 [5] 쓰레드 생성 예제 ( thread1_win.c) int main(int argc, char **argv) { HANDLE hThread; DWORD dwThreadID; hThread = (HANDLE)_beginthreadex(NULL, 0, ThreadFunction, NULL, 0, (unsigned *)&dwThreadID); if(hThread = = 0){ puts("_beginthreadex() error"); exit(1); } printf("생성된 쓰레드의 핸들 : %d \n", hThread); printf("생성된 쓰레드의 ID : %d \n", dwThreadID); Sleep(3000); /*millisecond 단위 */ puts("main함수 종료"); return 0; DWORD WINAPI ThreadFunction(void *arg) int i; for(i=0; i<5; i++){ Sleep(2000); puts("쓰레드 실행 중");
윈도우 기반의 쓰레드 생성 [6] 예제 실행 결과
윈도우 기반의 쓰레드 생성 [7] 커널 오브젝트, 리소스 그리고 핸들의 관계 . HANDLE h1 HANDLE h2 파 일 프로세스 스레드 . Program Area Kernel Area
Signaled & Non-Signaled 커널 오브젝트 [1] 쓰레드 커널 오브젝트의 상태 생성 시 : non-signaled 상태로 초기화 종료 시 : signaled 상태로 변경 커널 오브젝트 상태 확인 함수 #include <windows.h> DWORD WaitForSingleObject( Handle hHandle, // handle to object DWORD dwMilliseconds // time-out interval ); hHandle : 상태를 확인할 커널 오브젝트의 핸들을 전달 핸들의 커널 오브젝트 상태가 signaled가 되어야 리턴 Non-signaled 상태에 있을 경우 함수는 리턴하지 않고 대기상태 dwMilliseconds : 타임-아웃을 설정 커널 오브젝트가 signaled 상태로 바뀌지 않을 경우 무한 대기 상태로 빠짐 1/1000초(millisecond)단위로 설정 인자로 INFINITE를 전달할 경우 signaled 상태가 되기 전에는 절대 리턴하지 않음 리턴 값 : signaled 상태가 되어 리턴하는 경우에는 WAIT_OBJECT_0을 리턴 타임-아웃이 되어 리턴하는 경우 WAIT_TIMEOUT을 리턴 리턴 값을 비교해 결과를 확인
Signaled & Non-Signaled 커널 오브젝트 [2] WaitForSingleObject 함수 예제 int main(int argc, char **argv) { HANDLE hThread; DWORD dwThreadID; DWORD dw; hThread = (HANDLE)_beginthreadex(NULL, 0, ThreadFunction, NULL, 0, (unsigned *)&dwThreadID); if(hThread == 0){ puts("_beginthreadex() error"); exit(1); } printf("생성된 쓰레드의 핸들 : %d \n", hThread); printf("생성된 쓰레드의 ID : %d \n", dwThreadID); Sleep(3000); /*millisecond 단위 */ /* 쓰레드 종료 시까지 main함수의 실행을 지연 */ dw = WaitForSingleObject(hThread, INFINITE); if(dw == WAIT_FAILED) { puts("쓰레드 wait 오류"); exit(1); } printf("main함수 종료, %s 종료\n", dw==WAIT_OBJECT_0?"정상":"비 정상"); return 0; DWORD WINAPI ThreadFunction(void *arg) { int i; for(i=0; i<5; i++){ Sleep(2000); puts("쓰레드 실행 중");
Signaled & Non-Signaled 커널 오브젝트 [3] 예제 실행 결과
멀티 쓰레드 프로그래밍의 문제점 문제점 하나의 프로세스 내에서 생성된 쓰레드들은 스택을 제외한 나머지 메모리 영역을 공유 하나의 프로세스 내에서 생성된 쓰레드들은 스택을 제외한 나머지 메모리 영역을 공유 쓰레드간에 통신 하기는 편리하지만 쓰레드가 동시에 같은 메모리 영역에 접근할 경우 문제 발생 쓰레드를 동기화시킴으로 문제 해결
참고문헌 “TCP/IP 소켓 프로그래밍”, 윤성우 저
Q & A