소년코딩

프로세스와 스레드

컴퓨터에서 프로세스란 실행 중인 프로그램을 말한다. 일반적으로 컴퓨터 프로그램은 프로그래밍 언어로 작성된 후 컴파일 과정을 거쳐 오브젝트 파일(혹은 실행 파일) 형태로 하드디스크에 저장된다.

이렇게 하드디스크에 저장된 프로그램이 실행되기 위해서는 주기억장치로 적재되어 운영체제의 관리 개체로 등록되어야 하는데, 이 상태를 프로세스라 부른다.

1. 프로세스 속성

컴퓨터에는 여러 개의 프로세스가 동시에 존재하므로 각각의 프로세스를 식별하거나 관리하기 위해서는 아래와 같은 여러 가지 속성들이 필요하다.

프로세스 고유 번호(PID)

프로세스가 새로 탄생할 때마다 운영체제는 유일한 식별 번호를 부여한다.

어느 한 프로세스가 끝나면 그 프로세스가 차지하고 있던 PID는 이후에 탄생하는 다른 프로세스에 재할당될 수 있다.

프로세스 메모리 정보

하나의 연속된 메모리 공간 안에 여러 개의 프로세스가 존재하므로, 각각의 프로세스가 메모리의 어느 부분을 차지하고 있는지 관리되어야 한다.

만약 메모리 정보가 관리되지 않는다면 프로세스들 사이의 상호 침범을 탐지할 수 없을 것이다.

프로세스 상태(Process Status)

운영체제가 CPU를 어느 프로세스로 배정할 것인가를 탐색하기 위해서는 프로세스들이 입/출력이 완료되기를 기다리고 있는지 아니면 CPU 할당을 기다리고 있는지 등 프로세스의 현재 상태가 필요하다.

프로세스 진행지점(Program Counter)

운영체제가 선택한 프로세스에 CPU를 배정시켜주기 위해서는 프로세스별로 실행지점이 관리되어야 한다.

선택된 프로세스를 처리 중이던 CPU는 운영체제가 설정해 둔 타이머 인터럽트에 의해 언젠가는 그 프로세스를 떠나야 하는데, 이때 다음 실행할 기계 명령어에 대한 주소를 기록해두어야만 다음 기회에 연속된 처리가 가능하다.

프로세스 문맥(Process Context)

기계 사이클에서 본 것처럼, 모든 연산은 CPU 안에서 이루어진다. 피연산자나 연산결과가 저장되는 CPU 안의 저장 장소를 CPU 레지스터라 하는데, 어느 연산이 끝난 시점에서 인터럽트에 의해 CPU가 운영체제로 되돌아가면 조금 전 프로세스에서 생산된 CPU 레지스터값들이 파괴된다. 이렇게 되면 해당 프로세스를 나중에 다시 연속해서 실행할 때 이전의 연산 결과값들을 잃어버렸으므로 올바른 진행이 불가능하다.

그러므로 현재 진행 중인 프로세스의 연산 명령어들에 의해 CPU 안에서 생산되어 보관 중인 값들을 프로세스 문맥이라 하는데 이러한 문맥은 CPU가 진행 중인 프로세스를 떠날 때 보관되었다가 나중에 처리를 재개하지 직전에 복원되어야 한다. 이를 문맥 교환(Context Switching) 이라고 한다.

프로세스 우선순위(Process Priority)

운영체제는 CPU를 배정시킬 프로세스를 선택해야 하는데, 이때 필요한 요소가 우선순위다.

프로세스 우선순위는 최초에 기본으로 설정되었다가 CPU를 기다린 시간, 입/출력 여부, 메모리 포화 여부 등 주변 환경에 따라 운영체제에 의해 동적으로 조정되거나 관리자에 의해 변경될 수 있다.

프로세스 자원목록(Process Resource)

프로세스는 진행 도중 운영체제에 다양한 유형의 자원을 요청한다. 메모리 외에도 디스크 파일, 사운드, 그래픽 등의 물리적인 자원들과 네트워크 포트, 시그널 등 논리적인 자원들을 사용할 수 있는데, 프로세스별 할당 자원들이 관리되어야만 사후 자원의 회수 및 재활용을 할 수 있다.

회계 정보(Accounting Information)

프로세스 최초 생성부터 지금까지 머문 시간, CPU가 배정되어 실행된 시간, 메모리 사용량 등 프로세스의 성능이나 비용산정에 필요한 정보가 관리되어야 한다.

2. 프로세스 관리 블록(PCB: Process Control Block)

프로세스가 생성된다는 것은 프로세스가 운영체제에 의해 하나의 관리 개체로 등록됨을 의미한다.

이때 운영체제가 프로세스 관리를 위해 필요한 모든 정보를 기록하는 표를 PCB라 하고, 그 수는 생성 가능한 최대 프로세스 수를 의미한다.

PCB에는 위에 언급한 프로세스 속성들이 저장된다.

3. 스레드

프로세스의 연장 선상에서 사용되는 스레드 용어는 '실행 줄기' 정도로 설명할 수 있다. 프로세스는 프로그램의 시작 점(Entry point)에서 시작되는 명령어 처리의 흐름 줄기 즉, 실행 줄기를 갖게 되는데 이것이 곧 하나의 스레드이고 이 경우를 단일 스레드 프로세스라고 한다.

다시 말하면, 스레드는 프로세스의 구성 요소 중의 하나로서, 프로세스의 다른 구성 요소인 메모리(기계 명령어 및 데이터)를 따라 흐르는 개념적인 개체다.

스레드의 진정한 의의는 멀티 스레드 프로세스에서 찾을 수 있다.

4. 멀티 스레드 프로세스(Multi-thread Process)

멀티 스레드란 메모리에 적재된 프로그램(프로세스)의 시작 점이 여러 곳 있어서, 해당 프로세스를 바탕으로 진행하는 실행 줄기가 여러 개 존재한다는 의미다. 멀티 스레드 개념은 2개 이상의 CPU가 같은 프로세스 영역에 있는 기계 명령어를 실행하는 경우에서 쉽게 이해할 수 있다.

int S;

void main1()
{
  int x, y, z;
  x = 1, y = 2;
  z = add(x, y);
  S = S + z;
}

void main2()
{
  int a, b, c;
  a = 3, b = 4;
  c = add(a, b);
  S = S + c;
}

예를 들어 CPU1은 main1 함수부터 시작하고, CPU2는 main2 함수부터 시작한다면 이들은 각자의 제어 흐름에 따라 독립적으로 진행될 것인데, 이들 각각이 바로 스레드인 것이다.

이 스레드들이 main1과 main2 함수 부분을 실행할 때는 서로 다른 기계어 코드를 실행하겠지만, add 함수를 실행할 때는 완전히 같은 기계어 코드를 실행하게 된다. 이때 두 스레드가 거의 동시에 add 함수에 진입하면 각자의 계산 결과가 유지될까 하는 의문이 들 수 있다.

스레드들이 같은 기계 명렁어를 실행하더라도 연산 과정이 고유하게 유지되는데, 그 이유는 기계 명령어가 같더라도 피연산자를 위한 최종 목적 주소가 분리되어 있는 원리이기 때문이다.

즉, add 함수에서 사용되는 모든 변수는 지역 변수인데, 이들은 모두 CPU 내에 존재하는 SP(Stack Pointer)에 저장된 주소값을 기준으로 한 상대적 거리로 참조된다. 따라서 스레드 1을 위한 CPU1의 SP 값과 스레드 2를 위한 CPU2의 SP 값을 다르게 설정하면 add 함수의 기계어 코드는 같지만, 그 기계어 코드가 참조하는 최종 피연산자 주소는 다르다.

이처럼 스레드들의 고유성을 유지하기 위한 저장 공간을 스택(Stack) 영역이라 부르고, 스레드가 시작할 때 할당되며, 해당 스레드를 실행하는 CPU의 SP 값은 할당된 스택 영역으로 초기화된다.

멀티 스레드는 반드시 CPU가 여러 개 있어야만 의미 있는 것은 아니다. 운영체제가 CPU를 배정하는 단위를 프로세스가 아닌 스레드로 세분화시키기 때문에 하나의 프로세스 위를 여러 개의 스레드가 통과할 수 있다.

멀티 스레드 프로그래밍 환경에서 주의할 점은 변수 S와 같이 전역 변수를 동시에 참조하는 경우, 올바른 계산을 위해 동기화 장치가 필요하다는 것이다. 전역 변수 S는 상대 주소가 아닌 절대 주소로 참조되므로 해당 변수에 대한 스레드들의 참조 주소는 모두 같은 메모리 주소가 된다. 이런 경우 올바른 계산 결과를 얻지 못할 수 있다.


cpu

'컴구 이야기' 카테고리의 다른 글

7. 훑어보는 프로세스 동기화  (0) 2020.10.25
6. 훑어보는 CPU 스케줄링  (1) 2020.09.28
4. 훑어보는 입/출력 장치  (0) 2020.09.02
3. 훑어보는 인터럽트  (0) 2020.08.30
2. 훑어보는 컴퓨터 시스템 구조  (1) 2020.08.28
댓글 로드 중…

블로그 정보

소년코딩 - 소년코딩

소년코딩, 자바스크립트, C++, 물리, 게임 코딩 이야기

최근에 게시된 이야기