프로세스는 실행중인 프로그램이라고 생각할 수 있다.
- OS에서 작업의 단위이다.
- 자원을 필요로 한다.(CPU, 메모리, 파일, IO장치)
3.1 프로세스 개념
컴퓨터 내에서 일어나는 모든 활동을 프로세스라고 부를 수 있다.
3.1.1 프로세스
프로세스의 메모리 배치는 다음과 같다.

- 텍스트 섹션: 실행 코드
- 데이터 섹션: 전역 변수
- 힙 섹션: 동적 메모리
- 스택 섹션: 함수 호출 시 임시 데이터 저장장소(함수 매개변수, 복귀 주소, 지역 변수)
텍스트와 데이터 영역은 실행시간동안 크기가 변하지 않는다.
스택 및 힙 섹션은 동적으로 줄어들거나 커질 수 있다.
3.2.2 프로세스 상태 (Process State)
- New: 프로세스 생성
- Running: 프로세스 실행
- Waiting: 프로세스가 어떤 이벤트를 기다린다.(입출력 완료, 신호 수신)
- Ready: 프로세스가 처리기에 할당되기를 기다린다.
- Terminated: 프로세스 종료
한 순간 하나의 처리기 코어에는 오직 하나의 프로세스만 실행된다. 나머지 프로세스는 준비 및 대기 상태에 존재한다.
3.1.3 프로세스 제어블록 (Proceess Control Block)

- 프로세스 상태
- 프로그램 카운터: 해당 프로세스가 다음에 실행할 명령어의 주소
- CPU 레지스터: 프로세스가 다음에 실행될 때 필요한 데이터 정보
- CPU 스케줄링 정보
- 메모리 관리 정보
- 회계정보
- 입출력 상태 정보
3.1.4 스레드
대부분 현재 운영체제는 프로세스의 개념을 확장하여 한 프로세스가 다수의 스레드를 가진다.
- 한 번에 하나 이상의 일을 수행할 수 있다.
- 다중 처리기 시스템에서 이익이다. (ex: 워드프로세서에서 입력과 동시에 철자 검사)
3.2 프로세스 스케줄링
다중 프로그래밍의 목적은 CPU 이용을 최대화하기 위해 항상 어떤 프로세스를 실행하는 것이다.
- 프로세스 스케줄링을 통해 빈번하게 코어를 이용하는 프로세스를 변경한다.
- 메모리에 있는 프로세스 수를 다중 프로그래밍 정도라고 한다.
I/O 바운드 프로세스: 계산보다 I/O에 더 많은 시간을 소비하는 프로세스
CPU 바운드 프로세스: 계산에 더 많은 시간을 소비하는 프로세스
3.2.1 스케줄링 큐

준비큐에 실행 예정인 PCB가 삽입된다.
I/O 디바이스의 사용을 기다리는 경우 대기큐에서 해당 장치가 사용가능할 때까지 기다린다.
- I/O 장치는 프로세서보다 상당히 느리게 실행된다.
- 프로세스는 새 자식 프로세스 생성 후 자식의 종료를 기다리는 동안 대기큐에 놓일 수 있다.
3.2.2 CPU 스케줄링
CPU 스케줄러
CPU 스케줄러의 역할은 준비 큐에 있는 프로세스 중 하나를 선택하여 코어를 할당하는 것이다.
스와핑
메모리에서 프로세스를 제거하여 다중 프로그래밍 정도를 감소시키는 것이 유리할 수 있다.
- 메모리가 초과 사용되어 가용공간을 확보해야할 때 필요
- 프로세스를 디스크로 스왑아웃 후 현재 상태 저장 -> 디스크에서 메모리로 스왑인 하여 상태를 복원
3.2.3 문맥 교환

실행중이던 프로세스를 중단했다가 재개하는 작업이다.
- state save: 실행 중인 프로세스의 현재 문맥을 저장
- state restore: 실행할 프로세스의 문맥을 복구
문맥 교환 시간
- 문맥 교환 시간은 순수 오버헤드이다.
- 하드웨어 자원에 의해 크게 좌우된다.
- 운영체제가 복잡할수록 문맥 교환 시 해야 할 작업의 양이 많아진다.
3.3 프로세스에 대한 연산
프로세스들은 반드시 동적으로 생성되고 제거되어야 한다.
3.3.1 프로세스 생성
부모 프로세스: 생성하는 프로세스
자식 프로세스: 생성된 프로세스
프로세스 식별자(pid)를 이용하여 프로세스를 구분한다.
- pid는 정수
- 고유한 값을 가지도록 할당된다.
자식프로세스가 실행되기 위해서는 자원을 필요로 한다.
부모 프로세스에 할당된 자원의 일부를 사용하게 함으로서 시스템 과부하를 일으키는 프로세스를 방지할 수 있다.
부모 프로세스는 자식 프로세스에게 초기화 데이터를 입력할 수 있다.
생성된 프로세스가 실행되는 두가지 방법
- 부모는 자식과 병행하게 실행을 계속한다.
- 부모는 일부 또는 모든 자식이 실행을 종료할 때까지 기다린다.
wait()
시스템 콜을 통해 부모 프로세스는 자식이 종료될 때까지 자신을 준비큐에서 제거한다.
exit()
시스템 콜을 호출하여 프로세스를 종료한다.
새로운 프로세스
새로운 프로세스들은 주소 공간 측면에서 두가지 가능성을 가진다.
1. 자식 프로세스는 부모 프로세스의 복사본이다.
2. 자식 프로세스가 자신에게 적재될 새로운 프로그램을 가지고 있다.
일반적으로 fork()
시스템 콜을 호출하면 부모 프로세스의 복사본을 메모리에 적재한다.
이후 exec()
시스템 콜을 사용하여 자신의 메모리 공간을 새로운 프로그램으로 교체한다.

3.3.2 프로세스 종료
프로세스가 종료되는 경우는 두가지이다.
1. exit()
시스템 콜을 통한 자체 종료
- 부모 프로세스에 상태값을 반환할 수 있다.
- 할당된 자원이 해제되어 운영체제에 반납된다.
- 시스템 콜을 통한 다른 프로세스의 종료 유발
- 통상적으로는 부모->자식 프로세스 관계에서만 가능하다.
- 부모가 자식을 종료시키기 위해서는 pid값을 알아야 한다.
좀비 프로세스
특정 프로세스가 종료되면 종료 상태가 저장된다.
이는 부모가 wait()
를 호출할 때까지 남아있는다.
종료되었지만 아직 wait()
이 호출되지 않은 프로세스를 좀비 프로세스라고 한다.
고아 프로세스
부모가 wait()
을 호출하지 않고 종료한 경우 자식 프로세스들은 영원히 wait()
을 호출받을 수 없다. 이러한 프로세스들으 고아 프로세스라고 부른다.
- UNIX에서는 고아프로세스의 새로운 부모를 init 프로세스로 지정하여 문제를 해결한다.
- init 프로세스는 주기적으로
wait()
을 호출하여 종료상태 테이블 항목을 반환한다.
3.4 프로세스 간 통신 (Inter Process Communication)
프로세스 협력을 허용하는 환경을 제공하는 이유
- 정보 공유
- 계산 가속화: 특정 테스크를 서브테스크로 나누어 병렬로 실행한다.
- 모듈성
협력적 프로세스들은 데이터를 교환할 수 있는 프로세스 간 통신 기법이 필요하다.
프로세스 간 통신에는 기본적으로 두 가지 모델이 있다.
-
공유 메모리 (shared memory)
- 공유 메모리 영역 구축시에만 시스템 콜이 필요하다.
- 메시지 전달보다 통상적으로 더 빠르다.
-
메시지 전달 (message passing)
- 충돌을 회피할 필요가 없다
- 적은 양의 데이터 교환에 유리하다.
- 분산 시스템에서는 공유 메모리보다 구현이 쉽다.
- 시스템 콜을 사용하여 커널 간섭 등 부가적인 작업이 필요하다.
3.5 공유 메모리 시스템에서의 프로세스 간 통신 (IPC in shared-memory systems)
공유 메모리
-
통상 공유메모리 영역은 공유 메모리 세그먼트를 생성하는 프로세스의 주소 공간에 위치한다.
-
공유 메모리를 이용하는 다른 프로세스는 해당 세그먼트를 자신의 주소공간에 추가한다.
-
데이터의 형식과 위치는 이들 프로세스에 의해 결정되므로 운영체제의 소관이 아니다.
생산자-소비자 문제
- 생산자가 정보를 채우고 소비자가 정보를 소모할 수 있는 항목들의 버퍼가 사용가능해야한다.
- 생산자와 소비자가 반드시 동기화되어야 한다. -> 생산되지 않은 항목들의 소비 시도 방지
버퍼
무한 버퍼(unbounded buffer)
유한 버퍼(bounded buffer)
- 크기가 유한하다.
- 모든 버퍼가 채워져 있으면 생산자는 대기한다.
3.6 메시지 전달 시스템에서의 프로세스 간 통신 (IPC in message-passing systems)
Message-Passing 방식은 동일한 주소공간을 공유하지 않고 프로세스들이 통신하고 동기화할 수 있도록 허용한다.
네트워크에 의해 연결된 프로세스들이 존재하는 분산 환경에서 유용하다.
두가지 연산을 제공한다.
- send(message)
- receive(message)
통신 연결 방식
- 직접 또는 간접 통신
- 동기식 또는 비동기식 통신
- 자동 또는 명시적 버퍼링
3.6.1 명명 (Naming)
직접 통신
직접통신의 경우 각 프로세스는 송신자, 수신자의 이름을 명시해야 한다.
- send(P, message) - 프로세스 P에 메시지 전송
- receive(Q, message) - 프로세스 Q로부터 메시지 수신
특징은 다음과 같다.
- 상대방의 신원만 알면 각 프로세스 쌍 사이의 연결은 자동으로 구축된다.
- 연결을 정확히 두 프로세스 사이에만 연관된다.
- 통신하는 프로세스의 각 쌍 사이에는 정확히 하나의 연결이 존재해야 한다.
비대칭 적으로 송신자만 수신자의 이름을 지명하는 기법도 있다.
- send(P, message) - 프로세스 P에 메시지 전송
- receive(id, message) - 임의의 프로세스로부터 메시지 수신, 송신한 프로세스의 이름을 id에 저장
직접통신은 프로세스를 지정한다는 방식에서 모듈성을 제한한다는 것이 단점이다.
프로세스의 이름이 바뀌는 경우 해당 부분을 모두 찾아 변경하는 하드코딩이 필요하기때문에 바람직하지 않다.
간점 통신
메시지들이 메일박스(mailbox) 또는 포트(port)로 송신되고 그것들로부터 수신된다.
- send(A, message)- 메시지를 메일박스 A에 송신한다.
- receive(A, message) -메시지를 메일박스 A로부터 수신한다.
특징은 다음과 같다.
- 프로세스 간 연결은 같은 메일박스를 공유함으로써 구축된다.
- 연결은 두 개 이상의 프로세스들과 연관될 수 있다.
- 통신하고 있는 각 프로세스 사이에는 다수의 서로 다른 연결이 존재할 수 있고, 각 연결은 하나의 메일박스에 대응된다.
메일박스는 한 프로세스나 운영체제에 의해 소유될 수 있다.
-
프로세스가 소유하는 경우 메일박스를 소유한 프로세스가 수신자이므로 메일박스의 사용자와 소유자를 구분할 수 있다.
-
운영체제가 소유하는 경우 메일박스는 자체적으로 존재하고, 운영체제는 프로세스에게 메일박스를 사용할 수 있는 기법을 제공한다.
- 새로운 메일박스 생성
- 메일박스를 통한 메시지 송수신
- 메일박스 삭제
3.6.2 동기화 (Synchronization)
봉쇄형/동기식 (blocking)
- 봉쇄형 보내기: 송신하는 프로세스는 메시지가 수신될때까지 봉쇄된다.
- 봉쇄형 받기: 메시지가 이용 가능할 때까지 수신 프로세스가 봉쇄된다.
비봉쇄형/비동기식 (nonblocking)
- 비봉쇄형 보내기: 송신 프로세스가 메시지를 보내고 작업을 재시작한다.
- 비봉쇄형 받기: 송신하는 프로세스가 유효한 메시지 또는 널(null)을 받는다.
blocking은 메시지 작업이 완료될 때까지 다른 작업을 중지하는 것, nonblocking은 메시지 작업이 완료되지 않아도 계속 작업을 진행하는 것.
3.6.3 버퍼링 (Buffering)
메시지는 임시 큐에 들어간다.
임시 큐 구현 방식
-
무용량(zero capacity): 대기하는 메시지를 가질 수 없다. 따라서 송신자는 수신자가 메시지를 수신할 때까지 기다린다.
-
유한 용량(bounded capacity): 큐는 유한한 길이 n을 가진다. 링크가 다 차면 송신자는 큐 안에 공간이 이용가능해질 때까지 봉쇄된다.
-
무한 요량(unbounded capacity): 큐는 잠재적으로 무한한 길이를 가진다.
무용량은 버퍼가 없는 메시지 시스템, 다른 경우들은 자동버퍼링이라고 부른다.