LISTORY
[윈도우즈 시스템 프로그래밍] Windows에서의 쓰레드 생성과 소멸 본문
뇌를 자극하는 윈도우즈 시스템 프로그래밍 책 관련 유투브 강의 정리이다.
오늘 정리할 내용은 Windows에서의 쓰레드 생성과 소멸에 대한 내용이다.
YouTube 주소 Windows에서의 쓰레드 생성과 소멸
Windows에서의 쓰레드 생성과 소멸
⊙ 쓰레드의 생성
쓰레드의 생성은 프로세스와 비슷하다. 함수는 CreateThread()를 사용한다.
구성은 이와같이 되어있다.
각각의 인자에 대해 설명해보겠다.
첫 번째 인자는 보안관리자이다. 부모 자식간에 handle의 상속 여부를 결정한다.
두 번째 인자는 독립적인 stack 할당, 즉 사이즈 결정를 결정한다.
우리가 얼마나 주냐에 따라 stack의 사이즈가 결정된다. 보통 default로 준다.
세 번째는 함수 포인터, 함수를 가리킬 수 있는 포인터이다.
실제 선언은 다음과 같다.
typedef DWORD (WINAPI *PTHREAD_START_ROUTINE)(LPVOID lpThreadParameter);
위의 인자와 이름은 다르지만 typedef를 통해서 동일 시 된다.
이 함수의 전달인자로 LPVOID가 전달되는데, LPVOID는 VOID 포인터이다.
리턴타입으로는 DWORD를 리턴한다.
함수의 포인터
이 부분을 간단히 말하자면, 쓰레드가 필요로 하는 기능을 요구하는 형태의 함수로 만든다.
그리고 쓰레드를 생성할 때 이 함수의 이름을 세번째 인자로 전달하는 것이다.
이렇게 전달되는 함수.는 쓰레드 MAIN 함수가 된다.
이 쓰레드 메인 함수는 세번째 인자로 전달되고 전달됨과 동시에 함수가 호출되면서 쓰레드의 독립적인 루틴 형성한다.
그렇다면 VOID형 포인터를 어떻게 전달할까?
VOID형 포인터로 전달받겠다는 것은 원하는 타입으로 알아서 타입형변환해서 가져다 쓰라는 말이다.
하지만 실제 이쓰레드 함수는 우리가 직접 호출하는것이 아니라 윈도우즈에 의해 호출되기 때문에
인자 또한 윈도우즈에 요구해야한다.
이때 사용하는 것이 네번째 전달 인자이다. 여기에 함수에서 사용할 인자를 전달하면 된다.
다섯번째 인자는 사실 지금 이야기하기에 조금 이르다
간단히 말하자면 쓰레드를 생성하자마자 블럭디드 상태로 두는 경우에 사용하지만 그것 이외에도 중요한 요소가 있다.
이 부분은 다음에 설명하도록 하겠다.
프로세스도 생성 과정에서 ID를 얻을 수 있다. 마찬가지로 마지막 전달인자를 이용하여 THREAD의 ID를 얻을 수 있다.
근데 HANDLE과 ID의 차이는 무엇일까?
A라는 프로세스내에서 b라는 쓰레드를 생성했다.
이때 핸들은 A라는 프로세스 안에서 의미가 있다.
즉, b라는 쓰레드 커널 오브젝트에 접근하기 위해 핸들은 A는 쓰레드 내에서만 유효하다.
핸들은 프로세스가 뭔가를 컨트롤 하기 위해 사용하는 것이다.
반면 ID 는 좀더 범위가 넓다.
여러개의 프로세스를 생성해서 무수히 많은 쓰레드를 만들어도 쓰레드의 ID는 고유하다.
주로 윈도우즈 시스템에선 핸들을 이용한다.
* 생성 가능한 쓰레드의 개수는?
OS에서 지정할 수 있지만, 허용할 수 있는 만큼 허용하도록 디자인 한 경우도 많다.
그럼 허용의 기준이 무엇일까?
쓰레드를 생성할 때 메모리 구조상에서 보면 독립적으로 할당해주는 것이 STACK이다(공유할 수 없음).
그러므로 STACK은 쓰레드마다 각각 별도로 할당한다.
그렇다면 프로세스 32비트 기준, 즉, 4기가 안에서 허용할 수 있는 STACK의 한계치가 있다.
일단 2기가는 운영체제한테 할당해야 한다. 이 나머지에서 메모리가 허용하는 만큼 허용한다.
생성하는 쓰레드 별로 STACK을 할당하다가 더이상 할당할 수 없을만큼한다고 보면 된다.
⊙ 쓰레드의 소멸
CASE 1
쓰레드 종료 시 RETURN을 이용하면 좋은 경우(사실상 모든 경우)
CASE 2
쓰레드 종료 시 ExitThread 함수 호출이 유용한 경우( 특정 위치에서 쓰레드의 실행을 종료시키고자 하는 경우)
CASE 3
쓰레드 종료 시 Terminate Thread 함수 호출이 유용한 경우(외부에서 쓰레드를 종료시키고자 하는 경우)
쓰레드는 언제 종료할까?
일반적으로 쓰레드는 쓰레드의 main 함수(우리가 전달하는 함수)가 return을 하면 종료된다.
하지만 case2처럼 ExitThread를 통해서 쓰레드를 종료할 수 있다.
밑의 그림은 case1과 case2의 방법으로 쓰레드를 종료한 뒤 모습이다.
return 하는 방법으로 쓰레드 종료한 경우에는 호출된 함수의 순서대로 다 종료가 된다.
하지만 후자의 경우에는 그렇지 않다.
일반적으로 디자인을 잘한 쓰레드는 쓰레드의 main에서 return을 통해 종료해야하고 이렇게 하는 것이 안정적이다.
이 부분을 설명해보겠다.
a b c 함수가 있다. a는 쓰레드의 메인함수이다.
여기서 a가 b 함수를 호출하고, b가 c 함수를 호출했다.
c에서 종료해야만하는 시점을 말하기 앞서 쓰레드의 종료를 결정 짓는 대상은 메인쓰레드(a 함수)여야 한다.
b, c 함수는 쓰레드입장에서는 전역이다.
즉, 누구나 호출 가능해야한다.
a함수는 b와 c의 기능을 이용하기 위해 b와 c 함수를 사용하는 것이다.
근데 기능을 사용해야 하는 b와 c 함수에서 쓰레드를 종료시켜버리는 것은 안정성에 좋지 않다.
안정적이 위해선 쓰레드의 메인이 쓰레드의 종료를 결정지어야 한다.
결론을 말하자면 특정 위치에서 쓰레드에서 종료해야 하는 경우가 있지만 그렇게 하지 않도록 하는 것이 좋다.
CASE 3의 경우는 아예 사용하지 않는 편이 좋다.
'IT > 윈도우 프로그래밍' 카테고리의 다른 글
[윈도우즈 시스템 프로그래밍] 쓰레드의 상태 컨트롤 (0) | 2018.08.11 |
---|---|
[윈도우즈 시스템 프로그래밍] 쓰레드의 성격과 특성 (0) | 2018.08.11 |
[윈도우즈 시스템 프로그래밍] 커널 모드와 유저 모드 (0) | 2018.07.22 |
[윈도우즈 시스템 프로그래밍] 커널 레벨 쓰레드와 유저 레벨 쓰레드 (0) | 2018.07.22 |
[윈도우즈 시스템 프로그래밍] Windows에서의 프로세스와 스레드 (0) | 2018.07.15 |