초기의 컴퓨터 시스템: 한번에 하나의 프로그램만 실행 가능
오늘날의 컴퓨터 시스템: 메모리에 다수의 프로그램이 적재되어 병행 실행된다.
⇒ 이러한 발전은 다양한 프로그램을 보다 견고하게 제어하고, 구획화해야했다.
⇒ 이러한 필요성이 프로세스의 개념을 낳았다.
프로세스란 실행 중인 프로그램을 말하며, 현대의 컴퓨팅 시스템에서 작업의 단위이다.
비공식적으로, 프로세스란 실행 중인 프로그램이다. 프로세스의 현재 활동의 상태는 프로그램 카운터 값과 프로세서 레지스터의 내용으로 나타낸다.
다음은 프로세스의 메모리 배치이다. (여러 섹션으로 구분된다.)

⇒ text,data 섹션의 크기는 고정되어 있지만, stack 및 heap 섹션은 프로그램 실행 중에 동적으로 변화한다. 스택과 힙 섹션이 서로의 방향으로 커지더라도 운영체제는 서로 겹치지 않도록 해야한다.
프로그램 그 자체는 프로세스가 아니다!
프로그램은 명령어 리스트를 담고있는 디스크에 저장된 파일이다(실행파일) : 수동적인 존재
↔ 프로세스는 다음에 실행할 명령어를 지정하는 프로그램 카운터와 관련 자원의 집합을 가진 능동적인 존재이다.
⇒ 실행파일이 메모리에 적재될 때 프로그램은 프로세스가 된다.
프로세스는 실행되면서 그 상태가 변화한다.
상태 다이어그램 state diagram
⇒ 어느 한 순간에 한 처리기 코어에는 오직 하나의 프로세스만이 실행됨.
각 프로세스는 프로세스 제어블록 PCB에 의해 표현된다. 프로세스 제어 블록은 특정 프로세스와 연관된 여러 정보를 수록하며 다음과 같은 것들을 포함한다.
⇒ 프로그램카운터와 CPU레지스터의 상태코드는 나중에 프로세스가 다시 스케줄 될 때 올바르게 실행될 수 있도록 인터럽트 발생 시 저장되어야한다.
⇒ 요약하면 PCB는 약간의 회계 데이터와 함께 프로세스를 시작시키거나, 다시 시작시키는 데 필요한 모든 데이터의 저장소 역할을 한다.
대부분의 현대 운영체제는 프로세스 개념을 확장하여 한 프로세스가 다수의 실행 스레드를 가질 수 있도록 허용한다.
⇒ 따라서 프로세스가 한번에 하나 이상의 일을 수행 가능
다중 프로그래밍의 목적은 CPU 이용을 최대화하기 위해 항상 어떤 프로세스가 실행되도록 한다.
시분할의 목적은 각 프로그램이 실행되는 동안 사용자가 상호작용할 수 있도록 프로세스들 사이에서 CPU 코어를 빈번하게 교체하는 것이다.
⇒ 이를 달성하기 위해 프로세스 스케줄러는 코어에서 실행가능한 여러 프로세스 중에서 하나의 프로세스를 선택한다. (하나의 CPU코어는 하나의 프로세스를 실행가능하기 때문에 단일 코어는 한번에 하나의 프로세스 실행 / 다중 코어 시스템은 한번에 여러 프로세스 실행가능)
다중 프로그래밍 정도 : 현재 메모리에 있는 프로세스 수
프로세스의 성격
I/O 바운드 프로세스 : 계산에 소비하는 것보다 I/O에 더 많은 시간을 소비한다.
CPU 바운드 프로세스: 계산에 더 많은 시간을 사용하며, I/O 요청을 자주 생성하지는 않는다.
준비 큐:
프로세스가 시스템에 들어가면 준비 큐에 들어가서 준비 상태가 되어 CPU 코어에서 실행되기를 기다린다.
대기큐:

프로세스는 수명주기 동안 준비큐와 다양한 대기 큐를 이주한다.
CPU 스케줄러의 역할은 준비큐에 있는 프로세스 중에서 선택된 하나의 프로세스에 CPU 코어를 할당하는 것이다. ⇒ CPU를 할당하기 위한 새 프로세스를 자주 선택해야한다.
I/O 바운드 프로세스: I/O 요청을 대기하기 전에 몇 밀리초만 실행할 수 있다.
CPU 바운드 프로세스: 오랜시간 CPU 코어가 필요하다. (그렇지만 스케줄러는 프로세스에게 코어를 장기간 부여할 가능성이 없다.)
⇒ CPU 스케줄러는 적어도! 100밀리초마다 한번씩 실행된다.
스와핑
일부 운영체제는 스와핑으로 알려진 중간 형태의 스케줄링을 가지고 있다. 핵심 아이디어는 때로는 메모리에서 프로세스를 제거하여 다중 프로그래밍의 정도를 감소시키는 것이 유리할 수 있다는 것이다.
프로세스를 메모리에서 디스크로 “스왑 아웃”하고 현재 상태를 저장하고
이후 디스크에서 메모리로 “스왑인”하여 상태를 복원 할 수 있기 때문에 이 기법을 스와핑이라고 한다.
스와핑은 일반적으로 메모리가 초과 사용되어 가용 공간을 확보해야할 때만 필요하다. (9장 설명)
인터럽트는 운영체제가 CPU 코어를 현재 작업에서 뺏어내어 커널 루틴을 실행할 수 있게 한다.
인터럽트가 발생하면 시스템은 인터럽트가 끝난 후에 문맥을 복구할 수 있도록 현재 실행 중인 프로세스의 현재 문맥을 저장할 필요가 있다. 문맥은 프로세스의 PCB에 의해 표현된다.
CPU 코어를 다른 프로세스로 교환하려면 이전의 프로세스 상태를 보관하고 새로운 프로세스의 보관된 상태를 복구하는 작업이 필요하다. 이 작업을 문맥 교환(context switch)이라고 한다.

context switch가 진행될 동안 시스템이 아무런 유용한 일을 못하기 때문에 이 시간은 순수한 오버헤드다. 문맥 교환 시간은 하드웨어의 지원에 크게 좌우된다.
프로세스 생성 및 종료 기법을 알아보자.
UNIX, Linux 및 Windows와 같은 대부분의 현대 운영체제들은 유일한 프로세스 식별자(pid)를 사용하여 프로세스를 구분하는데 이 식별자는 보통 정수이다.

fork() 시스템 콜을 사용한 프로세스 생성
프로세스가 마지막 문장의 실행을 끝내고, exit 시스템 콜을 사용하여 운영체제에 자신의 삭제를 요청하면 종료한다. 이 시점에서, 프로세스는 자신을 기다리고 있는 부모 프로세스에게 wait 시스템콜을 통해 상태값을 반환할 수 있다.그리고 프로세스의 모든 자원이 할당 해제되고 운영체제로 반납된다.
또 다른 프로세스가 종료되는 경우는 부모 프로세스가 종료시키는 방법이다. 부모가 자식을 종료시키기 위해서는 자식의 pid를 알아야한다. 따라서 새로운 프로세스를 만들 때, 새로 만들어진 프로세스의 신원이 부모에게 전달된다.
부모는 다음과 같이 여러가지 이유로 자식 중 하나의 실행을 종료시킬 수 있다.
몇몇 시스템에서는 부모 프로세스가 종료한 이후에 자식 프로세스가 존재할 수 없다. 그러한 시스템에서는 프로세스가 종료되면 그로부터 비롯된 모든 자식 프로세스들도 종료되어야한다.
⇒ 이를 연쇄식 종료(cascading termination)이라고 하며, 이 작업은 운영체제가 시행한다.
좀비 프로세스: 종료되었지만 부모 프로세스가 아직 wait()을 호출하지 않은 프로세스. 종료하게 되면 모든 프로세스는 좀비상태가 되지만 대게는 아주 짧은 시간동안만 머무른다.
고아 프로세스: 부모 프로세스가 wait()을 호출하는 대신에 종료하는 경우다. ⇒ UNIX는 고아 프로세스의 새로운 부모 프로세스로 init 프로세스를 지정함으로써 이 문제를 해결한다. init 프로세스는 주기적으로 wait()을 호출하여 고아 프로세스의 종료 상태를 수집한다.
운영체제 내에서 실행되는 병행 프로세스들은 독립적이거나 또는 협력적인 프로세스들이다.
독립적인 프로세스: 프로세스가 시스템에서 실행 중인 다른 프로세스들과 데이터르 공유하지 않는 프로세스
협력적인 프로세스: 프로세스가 시스템에서 실행 중인 다른 프로세스들에 영향을 주거나 받는다.
프로세스 협력을 허용하는 환경을 제공하는 데는 몇가지 이유가 있다.
⇒ 협력적 프로세스들은 데이터를 교환할 수 있는 프로세스 간 통신(IPC: interprocess communication) 기법이 필요하다.
프로세스간 통신에는 기본적으로 공유 메모리와 메세지 전달의 두가지 모델이 있다.
공유 메모리 모델: 협력 프로세스들에 의해 공유되는 메모리 영역이 구축된다. 프로세스들은 그 영역에 데이터를 읽고 쓰고 함으로써 정보 교환이 가능하다.
메세지 전달 모델: 통신이 협력 프로세스 사이에 교환되는 메세지를 통하여 이루어진다.
다음 그림에 이 두 모델이 대비되어있다. 많은 시스템이 이 두가지를 모두 구현한다.

공유 메모리 모델 vs 메세지 전달 모델
메세지 전달 모델은 충돌을 회피할 필요가 없기 때문에 적은 양의 데이터를 교환하는데 유용하다. 또한 분산시스템에서 공유메모리보다 구현하기 쉽다.
메세지 전달 시스템은 통상 시스템 콜을 사용하여 구현되므로 커널 간섭등의 부가적인 시간 소비 작업이 필요하기 때문에 공유 메모리 모델이 메세지 전달보다 더 빠르다! 또한 공유 메모리 시스템에서는 공유 메모리 영역을 구축할 때만 시스템 콜이 필요하다. 공유 메모리 영역이 구축되면 모든 접근은 일반적인 메모리 접근으로 취급되어 커널의 도움이 필요 없다.
일반적으로 운영체제는 한 프로세스가 다른 프로세스의 메모리에 접근하는 것을 금지한다. 공유 메모리는 둘 이상의 프로세스가 이 제약 조건을 제거한다는 것에 동의하는 것을 필요로 한다. 그런 후에 프로세스들은 공유 영역에 읽고 씀으로써 정보를 교환할 수 있다. 데이터의 형식과 위치는 이들 프로세스에 의해 결정되며 운영체제의 소관이 아니다.
협력하는 프로세스의 개념을 설명하기 위해, 협력하는 프로세스의 일반적인 패러다임인 생산자- 소비자 문제를 생각해보자. 생산자-소비자 문제의 하나의 해결책은 공유 메모리를 사용하는 것이다. 생산자와 소비자가 동기화 되어야 생산되지도 않은 항목들을 소비자가 소비하려고 시도하지 않을 것이다.
메세지 전달 시스템은 최소한 두가지 연산을 제공한다.
그리고 프로세스 간의 통신 연결(communication link)가 설정되어야한다.
하나의 연결과 send()/recieve() 연산을 논리적으로 구현하는 다수의 방법은 다음과 같다.
3.4절에서 공유 메모리와 메세지 전달 기법을 사용하여 프로세스들이 통신 하는 방법에 대해 설명하였는데, 이 기법들은 클라이언트 서버 시스템의 통신에서도 사용가능하다. 이 절에서는 클라이언트 서버에서 사용할 수 있는 두가지 다른 통신 전략에 대해 설명한다.
소켓은 통신의 극점을 뜻한다. 각 소켓은 IP주소와 포트 번호 두가지를 접합해서 구별한다.
일반적으로 소켓은 클라이언트-서버 구조를 사용한다. 서버는 지정된 포트에 클라이언트 요청 메세지가 오기를 기다린다. 요청이 수신되면 서버는 클라이언트 소켓으로 부터 연결요청을 수락함으로써 연결이 완성된다. 클라이언트 프로세스가 연결을 요청하면 호스트 컴퓨터가 포트번호를 부여한다.(이때 번호는 1024보다 크며 다른 프로세스와 다른 번호여야한다.)
소켓을 사용하면 다른 시스템의 두 프로세스가 네트워크를 통해 통신할 수 있다.
RPC는 다른 컴퓨터에 있는 프로세스에서 함수를 호출할 수 있는 방식으로 함수 호출 개념을 추상화한다. IPC와 많은 측면에서 유사하며, 사실 IPC 기반 위에서 만들어진다. 그러나 여기서는 프로세스들이 서로 다른 시스템 위에서 돌아가기 때문에 원격서비스를 제공하기 위해서는 메세지 기반 통신을 해야한다.