프로그램

  • 어떤 작업을 위해 실행할 수 있는 파일

프로세스

  • 프로그램을 실행해 운영체제로부터 시스템 자원(CPU와 RAM)을 할당받는 작업의 단위, 프로그램의 인스턴스
  • 프로세스가 유저모드에서 실행되면 커널이 메모리를 할당해줌 -> 이때 실제 메모리가 아니라 가상 메모리(RAM + HDD)를 할당해줌
  • 각각 독립된 메모리 영역(code, data, stack, heap)을 할당 받음
  • 한 프로세스는 다른 프로세스의 변수나 자료 구조에 접근 불가능, IPC를 사용해야함
  • 운영체제는 프로세스를 PCB(Process Control Block)라는 곳에 필요한 정보를 넣어두고 관리함

스레드

  • 프로세스가 할당받은 자원을 이용하는 실행의 단위 -> 스레드는 해당 자원으로 제한됨
  • 스레드마다 stack(통상적으로 1MB) , 레지스터 등을 할당받고 나머지는 공유
  • 각자 Thread Local Storage라는 공간을 가짐
  • 프로세스와 같이 TCB가 존재

멀티 프로세스와 스레드

  • 멀티 프로세스(멀티 태스킹) : 여러 프로그램을 동시에 사용
  • 멀티 스레드 : 하나의 프로그램을 여러 개의 스레드로 구성해 각 스레드가 하나의 작업을 처리, 스레드끼리는 데이터를 공유하기 때문에 효율적인 처리가 가능, 하나의 프로그램안에서 동시에 여러 작업을 수행하기 위해서 사용
  • 여러 프로세스나 스레드가 동시에 자원에 접근할 때 더 많은 자원을 확보하기 위한 경쟁조건(Race Condition)이 생김
  • 여기서 동시성 및 동기화이 중요하고 이를 위해 시분할사용이라는 개념이 등장

※ 윈도우는 멀티 스레드 중심, 리눅스는 멀티 프로세스 중심

가상 메모리

  • Code : 기계어 코드
  • Data : 전역 및 정적 변수
  • Stack : 지역 변수
  • Heap : 동적 할당 변수(malloc)

PCB(Process Control Block)

  • PID : Process의 ID(32bit 정수)
  • 프로세스의 상태
  • 기계어 코드의 주소 등이 포함됨

프로세스 상태

  • 생성 상태 : 막 생성된 상태
  • 준비 상태 : 입출력을 완료하고 연산할 준비(디스패치 : 준비 상태 -> 실행 상태)
  • 실행 상태 : 연산하는 단계(+PCB)
  • 완료 상태 : 실행이 끝난 상태(-PCB)
  • 대기 상태 : 실행 상태에서 입출 력을 위해 대기하는 상태
  • 보류 상태 : sleep(자발적) 대기열에서 이탈하고 재진입하기 때문에 플러스 알파의 시간이 추가적으로 소요됨
  • 휴식 상태 : suspend(외부요인) 대기열에서 이탈하고 재진입하기 때문에 플러스 알파의 시간이 추가적으로 소요됨

문맥 교환(Context Switching)

  • 하나의 코어가 다수의 프로세스를 처리할 때, 하나의 프로세스가 일정 시간 처리되고 PCB에 상태를 저장한 후 다음 프로세스로 넘어감. 이때 흐름이 일시정지 되고 다시 이어서 실행될 때 문맥이 교환된다고 함

프로세스의 생성과 복사

  • 생성 -> 메모리 복사(실행 코드 복사 등) -> PCB 생성 (복잡한 과정) 
  • Win32 API : CreateProcess(), ExitProcess(), WaitForSingleObject()
  • UNIX : fork(), exec(), exit(), wait()
    fork는 자식 프로세스를 생성할 때 새로운 프로세스를 생성하는 것과 같이 메모리를 새로 할당
    exec는 새로운 메모리를 할당하지 않고, 부모 프로세스의 메모에 자신을 덮어씌움

https://learn.microsoft.com/ko-kr/sysinternals/downloads/process-explorer

 

Process Explorer - Sysinternals

프로세스가 열어 둔 어떤 파일, 레지스트리 키, 기타 개체, 로드한 DLL 등을 찾으세요.

learn.microsoft.com

#include <iostream>
#include <Windows.h>
#include <process.h>

int g_data;
boolean g_bFlag = true;

HANDLE g_hThreadExit01, g_hThreadExit02, g_hThreadExit03;

void threadFunction01(void* pArg)
{
	std::cout << "threadFunction01 - Start\n";

	while (g_bFlag) {
		g_data = 1000;
	}

	std::cout << "threadFunction01 - End\n";
	::SetEvent(g_hThreadExit01);
}

void threadFunction02(void* pArg)
{
	std::cout << "threadFunction02 - Start\n";

	while (g_bFlag) {
		g_data = 2000;
	}

	std::cout << "threadFunction02 - End\n";
	::SetEvent(g_hThreadExit02);
}

void threadFunction03(void* pArg)
{
	for (int i = 0; i < 10; i++) {
		std::cout << "threadFunction03() g_data: " << g_data << std::endl;
		Sleep(0); //우선순위에서 물러나서 뒤로 빠짐 -> 하기 전과 후에 영향을 미침
	}

	::SetEvent(g_hThreadExit03);
}

int main()
{
	std::cout << "Hello World - Start\n";

	g_bFlag = true;
	g_hThreadExit01 = ::CreateEventA(nullptr, TRUE, FALSE, "T_THREAD_01");
	g_hThreadExit02 = ::CreateEventA(nullptr, TRUE, FALSE, "T_THREAD_02");
	g_hThreadExit03 = ::CreateEventA(nullptr, TRUE, FALSE, "T_THREAD_03");

	::_beginthread(threadFunction01, 0, nullptr);
	::_beginthread(threadFunction02, 0, nullptr);

	::Sleep(10);
	::_beginthread(threadFunction03, 0, nullptr);

	//호출자 스레드 대기상태 전환
	//::Sleep(100); //우연에 맡기는 코드

	::WaitForSingleObject(g_hThreadExit03, INFINITE);
	g_bFlag = false;


	//T1, T2의 종료 이벤트를 대기
	::WaitForSingleObject(g_hThreadExit01, INFINITE);
	::WaitForSingleObject(g_hThreadExit02, INFINITE);

	::CloseHandle(g_hThreadExit01);
	::CloseHandle(g_hThreadExit02);
	::CloseHandle(g_hThreadExit03);
	std::cout << "Hello World - End\n";
}

'💻 Computer Science > OS' 카테고리의 다른 글

[OS] 교착상태  (0) 2023.12.18
[OS] IPC  (0) 2023.12.18
[OS] 스케줄링  (0) 2023.12.18
[OS] 운영체제  (0) 2023.12.15
[OS] 컴퓨터 구성  (0) 2023.12.15