개요
프로세스는 실행 중인 프로그램을 의미한다.
프로그램이 실행을 위해 메모리 할당이 되고, 메모리에 코드가 올라가면 이때부터, 프로그램이 프로세스가 된다.
프로세스 구성 요소
메모리: 스택, 힙, 데이터, 코드 영역을 사용한다.
레지스터 셋: 레지스터들은 프로그램의 실행을 위한 데이터들로 채워지기 때문에 레지스터도 프로세스의 일부라고 할 수 있다.
프로세스 스케줄링
CPU는 하나이지만 프로세스는 여러 개를 실행시켜야하므로, 여러 프로세스를 교체하며 실행할 필요가 있다.
실제로는 여러 개의 프로그램이 동시에 실행되는 것 처럼 보이지만, 하나의 코어에서는 한순간에 하나의 프로세스만 실행가능하고, 너무 빠르게 교체되기 때문에 동시에 실행된다고 느낄 뿐이다.
프로세스의 CPU 할당 순서 및 방법을 결정하는 것을 스케줄링이라고 한다.
스케줄링 알고리즘을 통해 스케줄링 방식을 정한다.
기본적으로는 A, B, C 프로그램이 있을 때 A가 종료되면 B, B가 종료되면 C가 실행되는 방식을 생각할 수 있지만,
1. 해당 프로그램이 모두 끝날 때 까지 기다리는 시간이 오래걸림
2. 실제로 프로그램은 실행 중 시간을 항상 CPU만 사용하는 것이 아니고 IO에 많은 시간을 사용함
의 이유로 프로그램 중간에 CPU의 실행시간을 나눠 할당받아 실행하게 된다.
cpu를 많이 사용하는 process를 cpu bound process, io작업을 많이하는 process를 io bound process라고 부른다.
IO작업을 하는 도중에는 다른 프로세스에게 CPU를 넘겨도 문제가 없다.
예를 들어 인터넷에 어떠한 자료를 요구하고 이 자료가 도착하는데 30초가 걸린다면 해당 기간동안에는 다른 프로그램이 아무것도 동작하지 않고 기다리는 것 보다, 다른 프로세스가 실행될 수 있도록 자원을 넘겨야 한다는 것이다.
프로세스의 상태 변화

운영체제에서는 프로세스를 효과적으로 관리하기 위해서 여러가지 상태로 표현한다.
프로세스는 생성되고 소멸되는 과정 사이에 아래와 같은 상태 전이들을 겪을 수 있다.
1. Start(Create) -> Ready(Waiting)
-> 프로세스가 생성되어 Ready가 된다. CPU에 의해 실행되기를 희망하는 상태이다.
2. Ready(Waiting) -> Running
-> Ready상태에 있는 프로세스는 스케줄러에 의해 관리되며, 이후 선택되어 Running 상태가 된다.
Running 상태에서는 CPU에 의해 실행된다.
3. Running -> Ready
-> CPU 시간 할당량(time slice)이 소진되었거나, 더 높은 우선순위의 프로세스가 Ready 상태로 도착한 경우, 현재 실행 중인 프로세스는 강제로 중단되고 Ready 상태로 돌아간다
4. Running -> Blocked
-> 실행 중인 프로세스가 IO작업을 하는 경우(외부 자원을 기다리는 상태) CPU를 배정받을 수 없기 때문에 Blocked 상태가 되어 IO작업이 끝날 때 까지 기다린다. + 비동기 이벤트
5. Blocked -> Ready
-> Blocked 상태에서 IO 작업이 끝나면, 다시 스케줄러에 의해 CPU를 할당받을 수 있기 때문에 Ready 상태가 된다.
컨텍스트 스위칭
운영체제는 여러 프로세스를 동시에 실행하는 것처럼 보이게 하기 위해, 실행 중인 프로세스를 중단하고 다른 프로세스로 전환하는 작업을 수행한다. 이 과정을 컨텍스트 스위칭이라고 한다.
컨텍스트 스위칭 시, 현재 실행 중이던 프로세스의 상태(레지스터 값, 프로그램 카운터, 스택 포인터 등)를 저장하고, 다음에 실행할 프로세스의 상태를 복원한다. 이러한 정보는 PCB(Process Control Block)와 같은 구조체에 저장된다.
이 과정은 CPU 자원을 소모하는 작업이며, 스케줄러의 개입과 문맥 저장/복원 작업이 반복되므로 잦은 컨텍스트 스위칭은 오버헤드를 증가시키고, 전체 시스템 성능 저하를 초래할 수 있다.
따라서 운영체제는 효율적인 스케줄링 전략을 통해 컨텍스트 스위칭의 빈도와 타이밍을 조절한다.
프로세스 생성
시스템 프로그래밍을 할 때는 프로그램 실행 중 다른 프로세스를 생성할 수 있다.
Windows에서는 CreateProcess 함수를 사용해 프로세스를 생성할 수 있다.
CreateProcess
CreateProcessA 함수(processthreadsapi.h) - Win32 apps
새 프로세스와 해당 기본 스레드를 만듭니다. 새 프로세스는 호출 프로세스의 보안 컨텍스트에서 실행됩니다. (ANSI)
learn.microsoft.com
BOOL CreateProcessA(
[in, optional] LPCSTR lpApplicationName,
[in, out, optional] LPSTR lpCommandLine,
[in, optional] LPSECURITY_ATTRIBUTES lpProcessAttributes,
[in, optional] LPSECURITY_ATTRIBUTES lpThreadAttributes,
[in] BOOL bInheritHandles,
[in] DWORD dwCreationFlags,
[in, optional] LPVOID lpEnvironment,
[in, optional] LPCSTR lpCurrentDirectory,
[in] LPSTARTUPINFOA lpStartupInfo,
[out] LPPROCESS_INFORMATION lpProcessInformation
);
1. lpApplicationName: 생성할 프로세스의 실행 파일 이름을 전달한다. 경로명을 지정하지 않으면 Current Directory 기반으로 실행 파일을 찾는다.
2. lpCommandLine: 새로 생성할 프로세스에 전달할 명령줄 전체 문자열을 의미한다. 일반적으로 실행 파일 경로와 함께 그 뒤에 이어지는 인자들을 포함한다.
- 만약 lpApplicationName을 NULL로 지정하면, 시스템은 lpCommandLine의 첫 번째 공백 전 토큰을 실행 파일 경로로 간주한다.
- 이 경우 해당 실행 파일의 경로 및 확장자가 명시되지 않았다면, 시스템은 .exe 확장자를 자동으로 붙이며 표준 검색 경로를 통해 파일을 찾는다.
- 단, 이때 첫 토큰은 MAX_PATH 문자 수 이내여야 하며, 초과할 경우 실패할 수 있다.
표준 검색 경로 순서:
- 호출하는 애플리케이션(EXE)이 위치한 디렉터리
- 부모 프로세스의 현재 작업 디렉터리 (Current Directory)
- System32 (32비트 시스템 디렉터리)
- System (16비트 시스템 디렉터리, 레거시)
- Windows 디렉터리 (C:\Windows)
- PATH 환경 변수에 나열된 디렉터리
또한, Unicode 버전(CreateProcessW)을 사용할 경우, 내부에서 명령줄 문자열을 변형하는 과정이 있으므로,
lpCommandLine에 상수 문자열 리터럴 (const TCHAR*)을 직접 전달하는 대신, 변수에 문자열을 복사한 후 전달하는 것이 안전하다.
3. lpProcessAttributes: process의 보안 속성(security attribute)을 지정한다. (NULL이면 default)
4. lpThreadAttributes: thread의 보안 속성을 지정한다. (NULL이면 default)
5. hInheritHandle: TRUE라면 자식 프로세스는 부모 프로세스의 상속 가능한 핸들을 상속한다.
6. dwCreationFlag: 생성하는 프로세스의 특성을 결정한다. 설정이 필요 없는 경우 0을 전달한다.
7. lpEnvironment: 생성하는 프로세스의 Environment Block(환경 블록)을 지정한다. NULL이면 부모 프로세스의 환경블록 내 문자열을 복사한다.
8. lpCurrentDirectory: 생성하는 프로세스의 Current Directory를 지정한다. NULL인 경우 부모 프로세스와 같게 만든다.
9. lpStartupInfo: STARTUPUINFO 구조체를 전달한다. STARTUPINFO 구조체는 프로세스의 속성을 지정한다.
10. lpProcessInformation: 생성하는 프로세스의 정보를 얻는다. PROCESS_INFORMATION 구조체 변수의 주소값을 전달한다. CreateProcess 실행 후에 전달한 인자 내에 프로세스 정보가 채워진다.
STARTUPINFO
STARTUPINFOA(processthreadsapi.h) - Win32 apps
생성 시 프로세스에 대한 주 창의 창 스테이션, 데스크톱, 표준 핸들 및 모양을 지정합니다. (ANSI)
learn.microsoft.com
typedef struct _STARTUPINFOA {
DWORD cb;
LPSTR lpReserved;
LPSTR lpDesktop;
LPSTR lpTitle;
DWORD dwX;
DWORD dwY;
DWORD dwXSize;
DWORD dwYSize;
DWORD dwXCountChars;
DWORD dwYCountChars;
DWORD dwFillAttribute;
DWORD dwFlags;
WORD wShowWindow;
WORD cbReserved2;
LPBYTE lpReserved2;
HANDLE hStdInput;
HANDLE hStdOutput;
HANDLE hStdError;
} STARTUPINFOA, *LPSTARTUPINFOA;
1. cb(count of bytes): 구조체의 크기
2. lpReserved: 예약 NULL
3. lpDesktop: 프로세스에 대한 데스크톱 및 창 스테이션의 이름
4. lpTitle: 제목 표시줄에 표시되는 제목
5. dwX: dwFlags에 STARTF_USEPOSITION 을 지정하는 경우 dwX의 값은 왼쪽 위 모서리에 있는 x오프셋이다.
6. dwY: dwFlags에 STARTF_USEPOSITION 을 지정하는 경우 dwY의 값은 왼쪽 위 모서리에 있는 y오프셋이다.
7. dwXSize: dwFlags에 STARTF_USESIZE를 지정하는 경우 새 창의 너비이다.
8. dwYSize: dwFlags에 STARTF_USESIZE를 지정하는 경우 새 창의 높이이다.
9. dwXCountChars: STARTF_USECOUNTCHARS를 지정하는 경우, 새 콘솔 창의 화면 버퍼 너비이다.
10. dwYCountChars: STARTF_USECOUNTCHARS를 지정하는 경우, 새 콘솔 창의 화면 버퍼 높이이다.
11. dwFillAttribute: STARTF_USEFILLATTRIBUTE를 지정하는 경우 새 콘솔 창의 초기 텍스트 및 배경색이다.
12. dwFlags: 프로세스 창 생성 시 특정 STARTINFO 멤버가 사용되는지 여부를 결정한다.
13. wShowWindow: STARTF_USESHOWWINDOW를 지정하는 경우 ShowWindow 함수에 대한 nCmdShow 매개변수에 대한 값이 될 수 있다.
14. cbReserved2: 예약됨 = 0
15. lpReserved2: 예약됨 = NULL
16. hStdInput: STARTF_USESTDHANDLES를 지정하는 경우 멤버는 프로세스의 표준 입력 핸들이다. 지정하지 않으면 표준 입력의 기본값은 키보드 버퍼이다.
17. hStdOutput: STARTF_USESTDHANDLES를 지정하는 경우 멤버는 프로세스의 표준 출력 핸들이다. 지정하지 않으면 표준 출력의 기본값은 콘솔 창의 버퍼이다.
18. hStdError: STARTF_USESTDHANDLES를 지정하는 경우 멤버는 프로세스의 표준 오류 핸들이다. 지정하지 않는 경우 기본 값은 콘솔 창의 버퍼이다.
// ParentProcess.cpp
#include <stdio.h>
#include <tchar.h>
#include <Windows.h>
#define DIR_LEN MAX_PATH + 1
int _tmain(int argc, TCHAR* argv[])
{
STARTUPINFO si = { 0, };
PROCESS_INFORMATION pi;
si.cb = sizeof(si);
si.dwFlags = STARTF_USEPOSITION | STARTF_USESIZE;
si.dwX = 100;
si.dwY = 200;
si.dwXSize = 300;
si.dwYSize = 200;
si.lpTitle = const_cast<LPTSTR>(_T("I am a boy!"));
TCHAR command[] = _T("C:\\WinSystem\\ChildProcess\\x64\\Debug\\ChildProcess.exe 10 20");
TCHAR cDir[DIR_LEN];
BOOL state;
GetCurrentDirectory(DIR_LEN, cDir);
_fputts(cDir, stdout);
_fputts(_T("\n"), stdout);
SetCurrentDirectory(_T("C:\\WinSystem"));
GetCurrentDirectory(DIR_LEN, cDir);
_fputts(cDir, stdout);
_fputts(_T("\n"), stdout);
state = CreateProcess(
NULL,
command,
NULL, NULL, TRUE,
CREATE_NEW_CONSOLE,
NULL, NULL, &si, &pi
);
if (state != 0)
_fputts(_T("Creation OK! \n"), stdout);
else
_fputts(_T("Creation Error! \n"), stdout);
return 0;
}
// ChildProcess.cpp
#include <stdio.h>
#include <tchar.h>
#include <Windows.h>
int _tmain(int argc, TCHAR* argv[])
{
DWORD val1, val2;
val1 = _ttoi(argv[1]);
val2 = _ttoi(argv[2]);
_tprintf(_T("%d + %d = %d \n"), val1, val2, val1 + val2);
_gettchar();
return 0;
}
si를 지정하고 command에 child process의 이름(경로), 인자를 지정한다.
Create Process를 통해 child process를 생성하고 실행시킨다.
아래는 결과이다.

'C, C++ > 뇌를 자극하는 윈도우즈 시스템 프로그래밍' 카테고리의 다른 글
| [뇌를 자극하는 윈도우즈 시스템 프로그래밍] 8장 IPC 2 (0) | 2025.06.08 |
|---|---|
| [뇌를 자극하는 윈도우즈 시스템 프로그래밍] 6장 - 커널 오브젝트와 오브젝트 핸들 (0) | 2025.05.20 |
| [뇌를 자극하는 윈도우즈 시스템 프로그래밍] 4장 - 컴구조(2) (0) | 2025.05.17 |
| [뇌를 자극하는 윈도우즈 시스템 프로그래밍] 3장 WIN32 vs WIN64 (0) | 2025.05.15 |
| [뇌를 자극하는 윈도우즈 시스템 프로그래밍] 2장. 아스키코드 vs 유니코드 (0) | 2025.05.09 |