Windows OS - C/C++ App과 Process(프로세스) 기본
Windows OS의 프로세스
Windows OS에서 프로세스는 실행중인 프로그램의 Instance라고 정의된다.
프로세스에 관련된 내용은 정말로 방대하지만,
우선은 기본적으로 간략한 내용들만을 다루기로 한다.
프로세스는 두개의 컴포넌트로 구성된다.
1. 프로세스 관리를 위해 운영체제가 사용하는 커널 오브젝트.
2. 프로세스 실행 모듈 Code, DLL Code, Thread Stack과 Heap 등을 위한 메모리 블럭.
프로세스는 절대로 자력으로 실행될 수 없다.
프로세스의 Context를 실행하는 주체는 어디까지나 Thread이다.
따라서 OS가 프로세스를 생성하면 일단은 무조건 1개의 스레드가 기본적으로 생성되는데,
이를 주 스레드(Primary Thread) 라고 부른다.
프로세스내에 Thread가 없다면, 실행 주체가 없으므로 OS는 Process를 파괴하며,
프로세스가 사용중인 주소공간을 해제한다.
Application, 즉 프로세스는 어떻게 시작되는가?
운영체제는 직접적으로 진입점 함수를 호출하지 않는다.
프로세스 시작과 종료에는 Start Up Function이 있다.
운영체제는 C/C++을 실행시 main등과 같은 진입점 함수를 호출하는 것 대신,
C/C ++ 런타임 시작 함수 (CRT Start Up Function)를 호출한다.
main,WinMain 관계 없이, ANSI/UNICODE 사용 관계없이,
공통적으로 C/C++ 런타임 시작함수는 다음과 같은 일을 수행한다.
1. 새로운 프로세스의 전체 명령행을 가리키는 포인터를 획득한다.
2. 새로운 프로세스의 환경변수를 가리키는 포인터를 획득한다.
3. C/C++ Runtime Library의 전역변수를 초기화 한다.
4. C/C++ Runtime Library의 동적 메모리 할당함수들과 저수준 입출력 루틴이
사용하게 될 힙을 초기화 한다.
5. 모든 전역객체 및 정적 객체에 대해 생성자를 호출 한다.
그리고 main 계열 함수를 호출한다.그리고 main 계열 함수의 반환값을 받고,이를 parameter로 삼아 C/C ++ Runtime Library내의 exit함수를 호출한다.
exit 함수는 다음과 같은 일들을 수행한다.
1. _onexit 함수를 이용해서 Application에서 atexit로 등록한 함수들을 실행한다.
2. 모든 전역객체 및 정적 객체에 대해 소멸자를 호출 한다.
3. DEBUG 빌드의 경우 _CRTDBG_LEAK_CHECK_DF 가 설정된 경우
동적 C/C++ Runtime 메모리에서의 메모리 누수상황을
_CRTDumpMemoryLeaks 함수를 호출하여 알려준다.
4. 인자로 받았던 main 계열 함수의 반환값을 사용해 ExitProcess를 호출한다.
ExitProcess를 실행하면 운영체제는 프로세스를 종료하고 프로세스에 대한 Exit Code를 설정한다.
Process의 실행
프로세스의 내부 Thread들은 모두 자신만의 Register Set과 Thread Stack을 가진다.
CPU는 모든 프로세스의 각 Thread들에게 실행시간을 나누어준다.CPU 코어가 여러개인 경우, Windows OS는 각 CPU 코어가 서로 다른 Thread들을 실행하게 한다.Thread에 대한 Scheduling 은 커널만이 할 수 있다.
모든 Process는 명령행 인자를 가지며,
프로세스가 할당받은 메모리 블럭내부에 환경 블록(PEB)를 가진다.
실행파일의 이름은 무조건 들어가야 하기 때문에, 명령행 인자를 1개 이상 가질 수 밖에없다.
이는 GetCommandLine 계열 함수로 확인이 가능하다.
CreateProcess로 프로세스 를 생성하면, 명령행 인자가 \0으로 들어가게 할수 있는데,
이 경우는 CreateProcess의 lpApplicationName에 시스템에 위치한 실행파일의 주소를 넣은 경우이다.
이 경우 CommandLine에 nullptr를 넣어도 된다.
더 자세한 것은 아래의 msdn을 참고.
CreateProcessA function (processthreadsapi.h) - Win32 apps
Creates a new process and its primary thread. The new process runs in the security context of the calling process.
docs.microsoft.com
모든 프로세스는 프로세스 내부에 환경 블록을 가지는데,
이를 Process Environment Block, PEB라고도 부른다.
이는 아래의 msdn을 참고한다.
이 PEB는 나중에 따로 다시...
https://docs.microsoft.com/en-us/windows/win32/api/winternl/ns-winternl-peb
PEB (winternl.h) - Win32 apps
Contains process information.
docs.microsoft.com
프로세스의 종료
프로세스가 종료되면 다음과 같은 일들이 일어난다.
1. OS는 프로세스 내에 남아있는 스레드를 모두 종료시킨다.
2. OS는 프로세스 핸들 테이블을 참조하여, 프로세스가 사용했던
커널 오브젝트의 사용 카운트를 1 감소시킨다.
이 결과 사용 카운트가 0이 된 경우 해당 커널 오브젝트를 파괴한다.
3. 프로세스의 종료코드가 STILL_ALIVE에서 ExitProcess 혹은 TerminateProcess 로 전달한
인자로 설정된다.
4. 프로세스 커널 오브젝트의 상태가 시그널 상태가 된다.
5. 프로세스 커널 오브젝트의 사용 카운트가 1 감소한다.
Application은 어떻게 프로세스를 종료할 수 있는가?
프로세스를 종료할때 Application은 다음과 같은 4가지의 방법을 사용할 수 있다.
1. Primary Thread의 main함수의 반환. (CRT Start Up Function 이 일련의 해제 작업을 마치고 ExitProcess 수행.)
2. 프로세스내의 Thread 가 ExitProcess 함수를 직접 호출.
3. 다른 프로세스가 TerminateProcess를 직접 호출.
4. 프로세스 내의 Thread가 각자 종료되어 모든 Thread가 종료되는 방식.
1번을 제외한 2,3,4 번은 그리 바람직한 방법이 아니다.
2.
ExitProcess 를 호출했을때, OS는 프로세스와 프로세스내부의 모든 스레드를 종료시키며,
사용중이던 모든 커널 오브젝트에 대한 사용 카운트를 감소시키며,
프로세스와 스레드가 사용중이던 모든 메모리를 해제한다.
또한 인자로 전달된 값으로 종료코드를 설정한다.
허나, main 함수 반환이후 CRT Start Up Function이 수행하는 리소스 정리작업(전역,정적 객체 소멸자 호출 등)
을 사용할수 없으므로 피해야하는 방법이다.
3. ExitProcess와 마찬가지로 프로세스와 그에속한 Thread가 사용하던 모든 리소스는OS에 의해 해제된다. 허나 2번과 마찬가지로,main 함수 반환이후 CRT Start Up Function이 수행하는 리소스 정리작업을 사용할 수 없으며또한 해당 프로세스는 통지를 받지 못하고 종료되는 것 이기때문에 더욱 좋지 않다.
4. 이 경우는 어떠한 이유에서 ExitProcess도, TerminateProcess를 호출하지 못하고
Primary Thread가 종료된 경우 일어난다.
모든 Thread가 종료되면 OS는 프로세스가 살아있을 이유가 없다고 판단, 이를 종료하고
리소스를 해제한다.
프로세스의 종료코드는 마지막에 종료된 Thread의 종료코드로 설정된다.
Primary Thread가 main 함수 반환 이전에 종료된 경우이다.
ExitThread가 호출되면 해당 Thread는 그대로 종료된다.
다른 Thread들이 돌고 있으므로 프로세스는 종료되지 않는다.
ExitProcess가 다른 Thread에서 호출되면 2번이 되었을 것이다.
나중에 결국 다른 모든 Thread가 종료되게 되면 이 경우가 되는데,
main 함수 반환이후 CRT Start Up Function이 수행하는 리소스 정리작업이 없기 때문에
역시 좋지 않은 방법이다.
'Windows OS' 카테고리의 다른 글
Windows OS - Windows 제공 Reader/Writer lock SRWLock (0) | 2022.02.20 |
---|---|
Windows OS - CriticalSection Spinlock으로 사용하기 (0) | 2022.02.20 |
Windows OS - 스레드(Thread) 2편 (0) | 2022.02.01 |
Windows OS - 스레드(Thread) 1편 (0) | 2022.01.12 |
Windows OS - Kernel Object(커널 오브젝트) (0) | 2022.01.02 |
댓글
이 글 공유하기
다른 글
-
Windows OS - CriticalSection Spinlock으로 사용하기
Windows OS - CriticalSection Spinlock으로 사용하기
2022.02.20 -
Windows OS - 스레드(Thread) 2편
Windows OS - 스레드(Thread) 2편
2022.02.01 -
Windows OS - 스레드(Thread) 1편
Windows OS - 스레드(Thread) 1편
2022.01.12 -
Windows OS - Kernel Object(커널 오브젝트)
Windows OS - Kernel Object(커널 오브젝트)
2022.01.02