Vienna

Chapter 5) 프로세스 생성과 소멸 - 프로세스의 스케줄링과 상태 변화 본문

그외/뇌를 자극하는 윈도우즈 시스템 프로그래밍

Chapter 5) 프로세스 생성과 소멸 - 프로세스의 스케줄링과 상태 변화

아는개발자 2023. 4. 15. 23:30

CPU는 한 순간에 하나의 프로그램만 실행이 가능하다.

== 동시에 둘 이상의 프로그램을 실행시킬 수 없다는 뜻.

 

 프로세스의 스케줄링(Scheduling)

하나의 CPU가 여러 개의 프로세스를 번갈아 가면서 실행해야 동시에 실행(하는 것처럼 보이는 것이) 가능.

 

■ 스케줄링이란?

프로세스의 CPU 할당 순서 및 방법을 결정짓는 일.

 

이때 사용되는 알고리즘을 가리켜 스케줄링 알고리즘(Scheduling Algorithm)이라 한다.

그리고 스케줄링 알고리즘을 적용해서 실제로 프로세스를 관리하는 운영체제 모듈을 가리켜 *스케줄러(Scheduler)라 한다

* 소프트웨어적으로 구현되어 있으며, 운영체제를 구성하는 중요한 요소 중 하나.

■ 프로세스의 상태

(1) 생성 상태 (new)

프로세스는 생성과 동시에 **준비상태에 접어든다.

** 멀티 프로세스 환경에서는 이미 CPU가 임의의 프로세스를 실행 중에 있을 수 있기 때문.

 

(2) 준비 상태 (ready)

스케줄러로부터 선택될 수 있는 상태

 

(3) 실행 상태 (running)

스케줄러부터 선택되어 실행 중인 상태 (CPU를 할당받아 실행중인 상태)

 

(4) 대기 상태 (blocked)

실행 상태인 프로세스가 실행을 멈추는 상태로 들어가는 것. (스케줄러에 의해서 선택될 수 없는 상태)

일반적으로 ***I/O(데이터 입출력)에 관련된 일을 하는 경우에 발생.

*** 네트워크 프로그램의 경우에는 네트워크로 연결되어 있는 호스트와 데이터를 송수신하게 되는데 이것도 포함.

 

(5) 종료 상태 (terminated)

프로세스가 종료된 상태

프로세스가 종료되면 OS는 PCB와 프로세스가 사용한 메모리를 정리함.

 

■ 멀티 프로세스 운영체제의 단점: 컨텍스트 스위칭(Context Switching)

실행 중인 프로세스의 변경은 시스템에 많은 부하를 가져다 주기도 한다.

이유: CPU 내에 존재하는 레지스터들은 현재 실행 중에 있는 프로세스 관련 데이터들로 채워지기 때문.

 

running 상태의 프로세스의 데이터와 running 상태로 전이시킬 ready 상태의 프로세스의 데이터를 스왑하는 과정을 컨텍스트 스위칭이라고 한다.

 

즉, 실행하는 프로세스의 변경과정에서 발생하는 컨텍스트 스위칭은 시스템에 많은 부담을 준다.

 

■ 프로세스의 생성

◇ CreateProcess 함수의 이해

Windows에서 프로세스 생성을 돕기 위해 CreateProcess 함수를 제공하고 있다.

* 부모 프로세스(Parent Process): CreateProcess 함수를 호출하는 프로세스

* 자식 프로세스(Child Process): CreateProcess 함수에 의해 생성된 프로세스

 

BOOL CreateProcess(
    LPCTSTR lpApplicationName,	// 1
    LPTSTR lpCommandLine,	// 2
    LPSECURITY_ATTRIBUTES lpProcessAttributes,	// 3
    LPSECURITY_ATTRIBUTES lpThreadAttributes,	// 4
    BOOL bInheritHandles,	// 5
    DWORD dwCreationFlags,	// 6
    LPVOID lpEnvironment,	// 7
    LPCTSTR lpCurrentDirectory,	// 8
    LPSTARTUPINFO lpStartupInfo,	// 9
    LPPROCESS_INFORMATION lpProcessInformation	// 10
);

// If the function fails, the return value is zero.

 

1. lpApplicationName

생성할 프로세스의 실행 파일 이름 (경로를 생략하는 경우 현재 디렉토리에서 찾는다)

 

2. lpCommandLine

새로 생성하는 프로세스에 인자를 전달할 때 사용.

 

3. lpProcessAttributes

프로세스의 보안 속성 지정. 보통 NULL 전달. (이 경우 디폴트 보안 속성 지정)

 

4. lpThreadAttributes

쓰레드의 보안 속성 지정 시 사용. NULL을 전달할 경우 디폴트 보안 속성 지정.

 

5. bInheritHandle

TRUE인 경우, 생성되는 자식 프로세스는 부모 프로세스가 소유하는 핸들 중 일부를 상속.

 

6. dwCreationFlag

생성하는 프로세스의 특성(특히 우선순위)을 결정지을 때 사용되는 옵션.

특별히 설정할 필요가 없는 경우 0 전달

 

7. lpEnvironment

프로세스 마다 ****Environment Block 이라는 메모리 블록을 관리.

**** 이 블록을 통해 프로세스가 실행에 필요로 하는 문자열을 저장할 수 있다.

NULL이 전달되면, 자식 프로세스는 부모 프로세스의 환경 블록에 저장되어 있는 문자열을 복사하게 된다.

 

8. lpCurrentDirectory

생성하는 프로세스의 현재 디렉터리를 설정

NULL이 전달되면, 부모 프로세스의 현재 디렉터리가 새로 생성하는 자식 프로세스의 현재 디렉터리가 된다.

 

9. lpStartupInfo

*****STARTUPINFO 구조체 변수를 초기화한 다음에 이 변수의 포인터를 인자로 전달.

***** 생성하는 프로세스의 속성을 지정할 때 사용.

 

10. lpProcessInformation

생성하는 프로세스 정보를 얻기 위해 사용되는 인자.

PROCESS_INFORMATION  구조체 변수의 주소값을 인자로 전달.

 

/*
AdderProcess.cpp
프로그램 설명: main 함수의 전달인자를 더하는 프로그램
*/

#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;
}
/*
CreateProcess.cpp 
프로그램 설명: 덧셈 프로세스를 생성
*/

#include <stdio.h>
#include <tchar.h>
#include <windows.h>

#define DIR_LEN MAX_PATH+1

int _tmain(int argc, TCHAR* argv[]) {
	// 프로세스 생성 1단계: STARTUPINFO 구조체 변수의 생성 및 초기화
	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;
    
    	// 현재 Visual Studio 컴파일러에서 const wchar_t* 타입을 LPWSTR에 대입하는 것이 불가.
    	// 그래서 command 창에서 이 프로그램을 실행하여 인자를 넘겨주는 방식으로 실행 예정.
	si.lpTitle = argv[1];
    
	TCHAR command[] = _T("AdderProcess.exe 10 20");
	TCHAR cDir[DIR_LEN];
	BOOL state;

	GetCurrentDirectory(DIR_LEN, cDir);
	_fputts(cDir, stdout);
	_fputts(_T("\n"), stdout);

    // 프로세스 생성 2단계: 현재 디렉터리의 설정
	SetCurrentDirectory(_T("C:\\WinSystem"));

	GetCurrentDirectory(DIR_LEN, cDir);
	_fputts(cDir, stdout);
	_fputts(_T("\n"), stdout);
    
    
    // 프로세스 생성 3단계: CreateProcess 함수의 호출
	state = CreateProcess(
		NULL,
		command,
		NULL, NULL, TRUE,
		CREATE_NEW_CONSOLE,
		NULL, NULL, &si, &pi
	); // CreateProcess

	if (state != 0)
		_fputts(_T("Creation OK! \n"), stdout);
	else
		_fputts(_T("Creation Error! \n"), stdout);

	return 0;
}

 

  표준 검색경로

1. 실행중인 프로세스의 실행파일이 존재하는 디렉터리

2. 실행 중인 프로세스의 현재 디렉터리(Current Directory)

3. Windows의 시스템 디렉터리(System Directory)

4. Windows 디렉터리(Windows Directory)

5. 환경변수 PATH에 의해 지정되어 있는 디렉터리

 

#define _CRT_SECURE_NO_WARNINGS

/*
* Calculator.cpp
* 프로그램 설명
* 1. 사칙연산 프로그램
* 2. 개선되어야 할 예제
*/

#include <stdio.h>
#include <tchar.h>
#include <windows.h>

enum { DIV=1,MUL, ADD, MIN, ELSE, EXIT};

DWORD ShowMenu();
void Divide(double, double);
void Multiple(double, double);
void Add(double, double);
void Min(double, double);

int _tmain(int argc, TCHAR* argv[]) {
	
	PROCESS_INFORMATION pi;
	
	STARTUPINFO si = { 0, };
	si.cb = sizeof(si);

	TCHAR command[] = _T("calc.exe");
	SetCurrentDirectory(_T("C:\\WINDOWS\\system32"));

	DWORD sel;
	double num1, num2;

	while (true) {
		sel = ShowMenu();
		if (sel == EXIT)
			return 0;

		if (sel != ELSE) {
			_fputts(_T("Input Num1 Num2: "), stdout);
			_tscanf(_T("%lf %lf"), &num1, &num2);
		}

		switch (sel) {
		case DIV:
			Divide(num1, num2);
			break;
		case MUL:
			Multiple(num1, num2);
			break;
		case ADD:
			Add(num1, num2);
			break;
		case MIN:
			Min(num1, num2);
			break;
		case ELSE:
			ZeroMemory(&pi, sizeof(pi));
			CreateProcess(NULL, command, NULL, NULL,
				TRUE, 0, NULL, NULL, &si, &pi);
			break;
		}
	}

	return 0;
}

DWORD ShowMenu()
{
	DWORD sel;

	_fputts(_T("-----MENU-----\n"), stdout);
	_fputts(_T("1. Divide\n"), stdout);
	_fputts(_T("2. Multiple\n"), stdout);
	_fputts(_T("3. Add\n"), stdout);
	_fputts(_T("4. Minus\n"), stdout);
	_fputts(_T("5. Any other operations\n"), stdout);
	_fputts(_T("6. EXIT\n"), stdout);
	_fputts(_T("SELECTION >> "), stdout);
	_tscanf(_T("%d"), &sel);

	return sel;
}

void Divide(double a, double b)
{
	_tprintf(_T("%f/%f=%f\n\n"), a, b, a / b);
}

void Multiple(double a, double b)
{
	_tprintf(_T("%f*%f=%f\n\n"), a, b, a * b);
}

void Add(double a, double b)
{
	_tprintf(_T("%f+%f=%f\n\n"), a, b, a + b);
}

void Min(double a, double b)
{
	_tprintf(_T("%f-%f=%f\n\n"), a, b, a - b);
}
Comments