본문 바로가기

Windows/_System Programming

쓰레드(Thread)의 생성과 소멸

쓰레드 생성 :

HANDLE CreateThread(
     LPSECURITY_ATTRIBUTES lpThreadAttributes,  // 보안속성(TRUE : 상속, NULL : 상속제외)
     SIZE_T dwStackSize,                                      // 쓰레드의 스택 크기
     LPTHREAD_START_ROUTINE lpStartAddress,    // 쓰레드로 동작하기 위한 함수(쓰레드 main)
                                                                          // 리턴타입 DWORD, 매개변수 타입 LPVOID(void*)
     LPVOID lpParameter,                                       // 쓰레드 함수에 전달할 인자 지정
     DWORD dwCreationFlags,                                // 쓰레드 생성 및 실행을 조절
     LPDWORD lpThreadId                                      // 쓰레드 ID를 전달받기 위한 변수의 주소값
);



쓰레드 소멸 :

1. return(일반적, 안정적) :

쓰레드 함수에서 return 은 쓰레드 종료

main 쓰레드의 return 은 프로세스 종료

쓰레드 함수의 return 값은 그 쓰레드의 커널 오브젝트에 저장된다.

리턴값 획득 :

BOOL GetExitCodeThread(
      HANDLE hThread,                 // 종료코드를 얻기 위한 쓰레드의 핸들
      LPDWORD lpExitCode            // 얻게 되는 종료코드를 저장할 메모리 주소
);


2. ExitThread(특정 위치에서 쓰레드의 실행을 종료) :

현재 실행 중인 쓰레드를 종료

VOID ExitThread(
      DWORD dwExitCode             // 커널 오브젝트에 등록되는 쓰레드 종료 코드를 지정
);                                             // GetExitCodeThread 함수를 통해 종료코드 획득 가능

이 함수를 사용하면 언제 어디서나 쓰레드를 종료 시킬수 있다.


(참고 : C++ 프로그래밍을 할때 주의해야 한다.

예를 들어 A, B 함수에 C++ 객체가 존재한다고 할때 C 함수에서 ExitThread 함수로 쓰레드를 종료할 경우
A, B 함수의 스택 프레임에 존재하는 소멸자가 호출되지 않아 메모리 유출 현상이 발생할 수도 있다.
return 문에 의한 쓰레드 종료가 가장 좋다)


3. TerminateThread(외부에서 쓰레드를 종료) :

강제종료 함수

따라서 종료에 필요한 여러 가지 일들을 처리하지 못하고 바로 종료된다.

BOOL TerminateThread(
      HANDLE hThread,                 // 강제 종료할 쓰레드의 핸들
      DWORD dwExitCode              // 종료할 쓰레드의 종료코드를 인자로 전달
);


4. 프로세스로부터 쓰레드 분리

쓰레드는 생성과 동시에 프로세스의 핸들 테이블에 그 핸들이 등록되므로 Usage Count 가 2가 된다.

따라서 쓰레드 생성시 얻은 핸들을 CloseHandle 로 반환하면 Usage Count = 1 이 된다.
 
쓰레드를 종료하면 Usage Count = 0 이 되어 쓰레드 커널 오브젝트가 소멸된다.



쓰레드의 성격과 특성 :

공유 영역 사용 :

ex)

total 을 전역변수로 선언했다. 따라서 모든 쓰레드는 공유 total 을 가지고 덧셈연산을 진행한다.

최종결과를 main 쓰레드가 참조한다.


동시접근의 문제점 :

위 ex) 에서 둘 이상의 쓰레드가 전역변수 total 에 동시접근할 경우 문제점이 생긴다.


컨텍스트 스위칭은 연중에도 빈번히 일어날 수 있기에 둘 이상의 쓰레드가 같은 메모리 영역을 동시에 참조하는 것은 문제를 발생시킨다.

따라서 멀티 쓰레드 기반의 쓰레드를 생성해야 한다.

uintptr_t _beginthreadex(   // CreateThread 함수와 파라미터 순서와 의미가 같다.(자료형과 리턴형의 차이가 있다)
         void *security,
         unsigned stack_size,
         unsigned (*start_address)(void *),
         void *arglist,
         unsigned initflag,
         unsigned *thrdaddr
); 

_beginthreadex 함수를 사용하면

쓰레드 함수에 여러 파라미터를 전달할 수 있다.

각각의 쓰레드를 위해서 독립적인 메모리 블록을 할당한다.
(스택 공간 + 고유한 레지스터 값 + 현재 명령 주소)    // CreatThread 함수 (스택 공간)

따라서 return 과 endthreadex 함수를 사용하여 할당한 메모리를 해제해야 한다.

void _endthreadex(unsigned retval);  // ExitThread 함수와 동일



쓰레드의 상태 컨트롤 :

쓰레드의 상태 변화(Suspend & Resume) : // 프로세스 상태 변화와 개념이 같다.
                                                            // http://dakuo.tistory.com/entry/프로세스의-생성과-소멸

쓰레드의 커널 오브젝트 멤버 Suspend Count 는 쓰레드의 상태를 나타낸다.

Suspend Count = 0 : 현재 실행중인 쓰레드(Ready)

Suspend Count > 0 : Block 상태

DWORD SuspendThread(
        HANDLE hThread          // Suspend Count++ 할 쓰레드의 핸들
);

DWORD ResumeThread(
        HANDLE hThread          // Suspend Count-- 할 쓰레드의 핸들
);

이 함수들은 변경되기 이전에 Suspend Count 를 리턴한다.


쓰레드의 우선순위 컨트롤 :

프로세스의 우선순위는 기존 우선순위라고 표현한다.

쓰레드는 추가로 상대적 우선순위를 갖는다.

 Priority   의미 
 THREAD_PRIORITY_LOWEST  -2
 THREAD_PRIORITY_BELOW_NORMAL  -1
 THREAD_PRIORITY_NORMAL  0 (Default)
 THREAD_PRIORITY_ABOVE_NORMAL  +1
 THREAD_PRIORITY_HIGHEST  +2

예)

NORMAL_PRIORITY_CLASS (기존 우선순위 9) + THREAD_PRIORITY_LOWEST(-2) = 7

즉, 이 쓰레드의 최종우선순위는 7이다


쓰레드의 상대적 우선순위 변경 :

BOOL SetThreadPriority(
        HANDLE hThread,        // 우선순위를 변경할 쓰레드의 핸들
        int nPriority                  // 우선순위 상수값
);

int GetThreadPriority(
        HANDLE hThread         // 우선순위를 확인할 쓰레드의 핸들
);

'Windows > _System Programming' 카테고리의 다른 글

쓰레드(Thread) 실행순서 동기화  (0) 2010.03.04
쓰레드(Thread) 메모리 접근 동기화  (0) 2010.03.04
쓰레드(Thread)  (2) 2010.02.28
환경변수  (0) 2010.02.25
스케줄링 알고리즘과 우선순위  (0) 2010.02.25