: 여러 개의 프로세스를 하나의 그룹으로 묶어서 관리하거나 (*)sandbox를 만들어서 프로세스들이 수행하는 작업에 제한을 둘 때 사용하는 커널 오브젝트.
*sandbox : 제한 사항의 집합
IsProcessInJob() : 프로세스가 잡에 포함되어 있는지 확인
CreateJobObject() : 잡 커널 오브젝트 생성
AssignProcessToJobObject() : 프로세스를 잡 내에 배치
- 잡에 포함된 프로세스가 child process 생성시 동일한 잡에 포함된다.
- 프로세스가 잡의 제한 사항을 준수하기 위해 생성시 CREATE_SUSPENDED 옵션을 이용하여 생성하고 프로세스를 잡 내에 배치시킨 후 실행을 재개한다.
- 프로세스가 이미 잡에 포함되어 있다면 다른 잡에 할당될 수 없으며 해제될 수도 없다.
OpenJobObject() : 생성되어 있는 잡 커널 오브젝트 핸들을 얻을 때 사용
SetInformationJobObject() : 잡에 제한 사항 설정
QueryInformationJobObject() : 현재 제한 사항 확인 및 잡의 통계 정보 조회
TerminateJobObject() : 잡 내의 모든 프로세스 종료
GetProcessIoCounters() : 잡에 포함되지 않은 프로세스의 읽기, 쓰기, 기타 동작의 수행 횟수 및 바이트 수를 얻을 때 사용.
잡 통지(job notification)
- 잡에 할당된 CPU 시간이 소진될 경우 잡 내의 모든 프로세스는 강제 종료되고 잡 커널 오브젝트는 signal 상태가 된다.
- SetInformationJobObject()를 이용하여 CPU 시간을 할당하면 Nonsignal 상태가 될 수 있다.
- IOCP (I/O Completion Port)를 연결하여 잡 통지를 받을 수 있다.
GetQueuedCompletionStatus() : IOCP로부터 정보를 가져온다.
PID를 이용하여 전체 경로명 얻기
GetModuleFileNameEx() : 함수 호출 실패 위험 있음
GetProcessImageFileName() : 커널 모드 형태 반환
QueryFullProcessImageName() : 추천
Chapter 6 스레드 기본
CreateThread() : API
_beginthreadex : C/C++ RTL (추천)
스레드 종료
1) 스레드 함수 반환(추천)
2) ExitThread() 호출 (_endthreadex()가 낫다.)
ExitThread()
- 스레드에서 사용한 운영체제 리소스를 정리
- C/C++ RTL의 리소스 정리 안함. (메모리 누수)
_endthreadex()
- C/C++ RTL의 리소스 정리 후 ExitThread() 호출
3) TerminateThread() 호출
TerminateThread()
- 비동기 함수
- 소유했던 프로세스가 종료되지 않는다면 스레드 스택이 정리되지 않으므로 다른 스레드에서 접근 가능하다.
- DLL이 스레드 종료 통지를 받지 못 한다. GetExitCodeThread()
4) 프로세스 종료
C/C++ Run-Time Library에 대한 고찰
멀티스레드 어플리케이션과 표준 C RTL
: 표준 C RTL의 전역 변수는 멀티스레드 환경을 고려하지 않고 작성되었기 때문에 멀티스레드 환경에서 문제가 될 수 있다. 따라서 스레드 별로 적절한 데이터 블록의 생성이 필요하다.
_beginthreadex()
: 생성할 스레드를 위한 적절한 데이터 블록(_tiddata 구조체)을 할당한 후 CreateThread()를 호출하여 스레드를 생성한다.
ExitThread()
: 스레드 내에서 우리가 생성한 C++ 오브젝트의 소멸자를 호출하지 못한다는 단점과 _tiddata가 할당된 메모리 블럭을 해제하지 않기 때문에 메모리 누수가 발생한다. 따라서 ExitThread() 대신 _endthreadex()를 사용하여 스레드를 제거하는 것이 낫다.
CreateThread()
: C RTL 함수 호출시 _tiddata 블록의 존재여부를 판단하여 _tiddata 블록을 새로 할당하고 초기화한다.
=> 그렇다면 굳이 _beginthreadex()를 사용해야만 하는가?
YES
이유 1. CreateThread() 사용시 C/C++ 런타임 라이브러리가 제공하는 signal 함수 사용시 구조적 예외 처리 프레임이 준비되지 않기 때문에 signal 관련 함수 호출시 프로세스가 종료된다
이유 2. 스레드 종료 함수는 _tiddata 메모리 블럭을 해제하기 위해 _endthreadex()를 호출해야만 하는데 CreateThread()를 호출하면 EndThread()를 호출하고 싶지 않은가! _endthreadex()를 이용해야 한다.
_beginthread()와 _endthread()는 사용을 삼가한다.
속해 있는 스레드나 프로세스 핸들 얻기
GetCurrentProcess()
GetCurrentThread()
둘 다 pseudohandle을 반환
DuplicateHandle()을 이용하여 (*)pseudohandle을 복사하여 실제 핸들로 변환 가능하다.
(*)pseudohandle : 항상 자신이 속해 있는 스레드 또는 프로세스의 핸들을 가리킨다.
시간 사용 정보를 얻는 함수
GetProcessTimes()
GetThreadTimes()
ID값을 얻는 함수
GetCurrentProcessId()
GetCurrentThreadId()