프로세스
1. 프로세스의 상태
1) running
- 프로세스가 CPU를 점유하고 있는 상태. running 상태인 프로세스는 I/O 장치를 동기-블록 방식으로 사용하는 경우에는 blocked 상태로 전환되고, time-share OS 하에서 타이머에 설정된 시간이 경과하여 interrupt가 발생한 경우 ready 상태로 전환된다.
- 커널은 프로세스 관리자로서 프로세스와 분류가 다른 것으로 보므로, I/O 장치를 사용하는 등의 이유로 커널이 CPU를 점유하게 되었을 때 이를 두고 ‘커널이 running 상태로 전환되었다’라고 표현하지는 않는다. (CPU를 점유하는 프로세스가 다른 프로세스로 전환되는 메커니즘과 프로세스에서 커널로 전환되는 메커니즘은 다소 다르기도 하다.)
2) ready
- 현재 CPU를 점유하고 있는 프로세스가 있어 당장 CPU를 점유할 수 없는 경우, ready 큐에 자신의 차례가 올 때까지 대기하는 경우가 있다. 이때의 프로세스를 ready 상태에 있는 프로세스라 한다.
3) blocked
- 프로세스가 I/O 장치로부터 데이터를 읽거나 쓰는 등의 작업을 완전히 마친 이후에야 비로소 바로 다음 작업을 수행할 수 있는 경우가 있을 수 있다. 이 경우 프로세스는 blocked 상태로 전환되며, 이 경우 ready 상태일 때와 달리 다른 프로세스들이 CPU 사용을 끝낸 뒤라 하더라도 blocked 상태인 프로세스는 자신이 요청한 I/O 장치에 대한 작업이 끝나기 전까지 CPU를 점유하지 않는다.
4) suspended
- 현대의 컴퓨터는 프로그램이 실행되면 일단 모두 메모리에 로드하는데, 메모리의 용량은 한정돼있으므로 당연히 실행된 프로그램이 사용하는 메모리의 용량이 실제 메모리의 용량을 초과하는 경우가 있을 수 있다. 이 경우 우선순위가 낮은 프로세스는 디스크의 swap space로 옮겨지게 된다. (이러한 작업을 하는 스케줄러를 medium-term scheduler 또는 swapper라 한다.) 이처럼 프로세스가 디스크의 swap sapce로 옮겨져 있는 상태를 suspended 상태라 한다.
- suspended 상태의 프로세스는 외부에서 다시 메모리로 로드해야만 메모리에 로드될 수 있으며, 스스로 다시 메모리로 옮겨질 수 없다.
2. CPU/메모리 상에 저장되는 프로세스의 정보
1) context
- CPU가 프로세스를 점유하고 있을 때, CPU를 점유하고 있는 프로세스의 현재 정보를 context라 한다. 프로세스의 context를 구성하는 요소는 다음 요소가 있다.
(1) program counter: 현재 CPU가 수행중인 프로세스의 코드 부분의 메모리 주소가 저장된 레지스터.
(2) 각종 레지스터들: 프로세스로부터 받아온 정보로서 CPU의 ALU가 연산해야 할 정보들을 담아놓은 레지스터 또한 context를 구성한다.
(3) 메모리 상의 프로세스의 code, data, stack
(4) 메모리 상의 커널의 data, stack에 있는 PCB, 프로세스 커널 스택
- 프로세스가 I/O 장치 사용 등의 이유로 커널을 호출하거나 time-share OS여서 현재 프로세스에서 다른 프로세스로의 전환이 일어날 때, 현재 프로세스의 context가 메모리 상의 커널의 data 부분의 PCB에 저장되게 된다. 커널은 이 PCB에 있는 정보를 읽어 프로세스에서 커널로의 전환 또는 다른 프로세스로의 전환을 처리한다.
2) PCB(Process Control Block)
- PCB는 메모리 상의 커널의 data 부분에 저장되는 프로세스의 정보를 담고 있는 자료구조로, 프로세스의 context switch가 일어날 때 현재 수행 중이던 프로세스의 정보를 메모리에 저장하고 메모리에 저장돼있던 다른 프로세스의 정보를 CPU에 올리기 위해 필요한 정보를 모아놓은 것이다.
- 다음 요소로 구성돼 있다.
(1) 프로세스의 현재 상태
(2) 프로세스의 고유 ID
(3) 프로세스의 최근의 program counter 등 여러 레지스터 내용
(5) 기타(프로세스가 최근 로드한 파일 등)
3) context switch
- CPU를 점유하는 프로세스를 다른 프로세스로 전환하기 위해 (1)현재 프로세스의 context를 커널의 PCB에 저장하고 (2)커널의 PCB로부터 전환할 프로세스의 context를 읽어오는 일련의 과정을 context switch라 한다.
- CPU를 점유하는 프로세스가 단지 커널을 호출했다가 다시 프로세스로 돌아오는 과정을 context switch라 하지는 않는다. context switch는 그 과정에서 CPU의 캐시 메모리를 깨끗이 비우는 과정을 포함하는데, 이 과정으로 인해 추가로 소모되는 시간 등이 매우 크다. 그러나 커널을 호출했다가 다시 프로세스로 돌아올 뿐이라면 이러한 과정을 수행하지 않으므로, context switch와는 여러 측면에서 차이가 있다.
3. 멀티 스레드
1) 개념
- 같은 코드를 수행한다 하더라도 프로그램의 수행이 독립적일 필요가 있다면 메모리에 새로 독립된 프로세스를 추가하는 경우를 생각할 수 있으나, code나 data 같은 자원은 공유해도 무방하다면 굳이 새로 프로세스를 메모리에 추가하는 것은 낭비일 수 있다. 이 경우에, 하나의 프로세스 안에 CPU를 사용하는 프로그램 단위를 여러 개 둘 수 있다. 즉, 한 프로세스의 code와 data를 공유하나 CPU에 의해 코드를 수행하는 경로를 그 프로세스 안에 둘 이상 설정할 수도 있는 것이다. 이때 하나의 프로그램 단위를 ‘스레드’라 하며, 프로세스 안에 스레드가 하나인 것을 single-threaded, 둘 이상인 것을 multi-threaded라 한다.
- 멀티 스레드를 구축하는 경우 code, data 같은 자원은 공유하나, program counter나 레지스터, stack 같은 자원은 각 스레드마다 고유의 값을 갖는다.
- stack 자원을 각 스레드마다 독립적으로 갖는 이유: 스레드가 다르다는 것은 실행 흐름이 독립적이라는 것. stack 공간은 함수 호출 내역을 기록하는 공간으로, stack 공간을 각 스레드마다 독립적으로 할당하지 않으면 스레드별 실행 흐름의 독립성을 제대로 보장할 수 없기 때문.
2) 장점
-
메모리 자원을 절약할 수 있다. (메모리 내 프로세스 구조에서 code, data 영역은 공유하고 stack만 추가로 사용한다.)
-
스레드 하나가 blocked 상태가 되면 그 프로세스가 CPU를 점유하는 순서가 되었을 때 프로그램의 수행을 다른 스레드들이 맡으면 되므로, blocked 상태를 필요로 하지 않는 작업을 다른 스레드들이 맡아서 수행하도록 하면 프로세스의 응답성을 높일 수 있다.
-
같은 작업을 수개의 스레드들이 서로 협력하여 수행하도록 해 성능 향상을 얻을 수 있다.
-
멀티 프로세서 시스템의 경우, 각 스레드들이 서로 다른 CPU를 사용하게 해 성능 향상을 얻을 수 있다.
-
context switch 시 overhead가 훨씬 적어 응답시간이 훨씬 줄어든다.
-
스레드 간 통신이 훨씬 간단하다. (data 영역을 공유하므로, 전역변수 접근으로 스레드 간 통신이 간단히 구현된다.)
3) 단점
-
스레드끼리 같은 자원에 접근하는 일이 빈번할 수 있으므로 동기화에 주의해야 한다.
-
멀티 스레드를 커널 지원 없이 프로세스 스스로가 직접 구현하는 경우, 커널이 프로세스가 멀티 스레드를 갖고 있는지 알지 못해 커널의 지원을 받지 못한다.
-
어느 한 스레드의 오류로 프로세스 전체가 종료될 수 있다.
4) thread-safe
- 멀티 스레드 환경에서 여러 스레드가 동시에 공유자원에 접근할 때 의도에 맞게 작동하는 것을 thread-safe라 한다. 이를 보장하기 위해 프로세스는 공유자원에 접근하는 코드(critical section)에 관한 race condition을 적절히 해결해야 한다.
- 어떤 함수에 여러 스레드가 동시에 접근해도 언제나 같은 실행 결과를 보장하는 것을 reentrant라 한다. 함수가 공유자원을 전혀 사용하지 않으면 reentrant한 특성을 갖는다. (따라서 reentrant는 thread-safe보다 훨씬 협소한 개념으로, reentrant하다면 thread-safe하지만 역은 성립하지 않는다.)
4. 프로세스의 생성
- 부모 프로세스가 자식 프로세스를 생성하는 경우가 있다. 이 경우 부모-자식은 서로 트리 구조를 형성하며, 부모 프로세스는 자식 프로세스가 종료되기 전까지 종료되지 않는 관계를 갖는다. 원칙적으로 자식 프로세스가 종료되기 전까지 부모 프로세스는 수행이 중단되나, 자식 프로세스의 종료 여부와 무관하게 계속 수행이 되는 경우도 있다.
- 기본적으로, (1)부모 프로세스가 자식 프로세스를 생성할 시 메모리 상에 부모 프로세스와 다른 주소에 부모 프로세스와 모든 값이 동일한 새 자식 프로세스가 생성된다(fork). (2)자식 프로세스는 이렇게 새로 할당된 메모리 위치에 새로운 code와 data 값을 덮어쓰게 된다(execution).
- 원칙적으로 부모 프로세스와 자식 프로세스는 서로 다른 메모리 위치에 있기 때문에 공유하는 자원도 없으나, 경우에 따라 일부 자원을 공유하는 경우가 있다. 예를 들어 어떤 OS의 경우, fork를 할 때 ‘똑같은 내용을 그대로 메모리에 복사하는 것은 낭비’라는 생각으로 자식 프로세스에 대해서는 program counter와 레지스터 정도만 새로 메모리에 할당하고 나머지 자원은 부모 프로세스의 자원을 그대로 사용하는 경우가 있다. 그러다가 공유하던 자원의 값이 부모 프로세스와 자식 프로세스에서 서로 달라져야 하는 경우가 있을 수 있는데(같은 주소에 있는 변수의 값을 다르게 대입하는 경우 등) 이때가 돼서야 비로소 새 메모리를 할당해 사용하는 것이다. 이처럼 자원을 공유하다 필요가 생길 때 그제야 새 메모리를 할당해 사용하는 것을 COW(Copy-On-Write)라 한다.
5. 프로세스의 종료
1) 프로세스가 스스로 프로세스 종료 system call을 하는 경우(exit)
2) 부모 프로세스가 임의로 자식 프로세스를 종료시키는 system call을 하는 경우(abort)
- 자식 프로세스가 그 프로세스에 할당된 자원의 한계를 넘어서 사용할 때
- 자식 프로세스가 더 이상 필요하지 않을 때
- 부모 프로세스가 종료되도록 하는 system call이 발생했을 때
6. 프로세스 간 통신(interprocess communication, IPC)
- 원칙적으로 각 프로세스는 서로 다른 메모리 영역에 할당돼 있어 서로 독립적이나, 특정 경우에는 프로세스 사이에 서로 협력하여 작업을 처리하는 경우가 있다. 이러한 처리를 위해서는 프로세스 사이에 서로 통신을 할 수 있어야 한다. 프로세스 사이 통신 기술을 IPC라 하며, 개략적으로 한 프로세스에서 다른 프로세스로 메시지를 보낸다 할 때, (1)커널의 큐에 차례대로 메시지를 전달해 커널이 그 목적지 프로세스로 대신 메시지를 차례대로 전달하게 하는 모델과 (2)메모리 내 커널 영역이 아닌 제3의 공유영역에 메시지를 전달하고 목적지 프로세스가 그곳으로 직접 접근해 메시지를 얻어오게 하는 모델 두 가지가 있다.
- 두 모델은 각각 장단점이 서로 달라, 두 모델이 모두 구현돼 있어 필요한 경우에 각 모델이 선택적으로 사용된다.
1) 커널을 통한 메시지 전달 모델
-
단점: 커널을 거치기 때문에 전달 속도가 공유 메모리 모델에 비해 다소 늦지만, 멀티 프로세스 환경에서는 공유 메모리 모델이 캐시 일관성 문제로 인해 오버헤드가 커 오히려 커널을 통한 전달 방식이 더 빠른 경우도 있다.
-
장점: 공유 메모리 모델에 비해 분산 시스템에서 구현이 쉽다.
(1) (익명) 파이프
- 파이프는 커널을 통해 한 프로세스에서 다른 프로세스로 직접 메시지를 전달하는 방식으로, 메시지를 송출할 프로세스와 메시지를 수신할 프로세스 사이에 ‘파이프’로 불리는 연결을 형성한 후 메시지를 전달한다. 이때 파이프는 단방향이며, 메시지가 들어온 순서대로 차례대로 수신측 프로세스에 전달된다(FIFO).
- 하나의 파이프는 한 방향으로만 메시지를 보낼 수 있으므로, 수신측 프로세스가 송신측으로 메시지를 송출하려면 새로운 파이프 연결을 추가로 형성해야 한다.
- 기본적으로 부모 - 자식 프로세스 사이 또는 형제 프로세스 사이에 통신할 때에만 사용 가능한 통신 방식이다.
- 이러한 관계가 없는 프로세스 사이에 사용하려면 수신측 프로세스의 이름을 적어놓은 특수한 파일을 사용해야 하며, 이때 사용하는 파이프에 이처럼 이름이 붙는다 하여 이 파이프를 named pipe라 한다. named pipe를 위한 파일은 커널 내 버퍼 메모리에 저장된다.
(2) 메시지 큐
- 커널에 할당된 공간(메시지 큐)에 메시지를 담아 전달한다. IPC를 원하는 여러 프로세스가 각각 메시지 큐에 메시지를 전달하면, 커널은 메시지 큐의 메시지들을 각 프로세스에 차례대로 전달한다(FIFO).
2) 공유 메모리 모델
- 처음에 커널에 메모리를 공유할 것을 요청하여 메모리 상의 공유 영역을 설정하고, 이후 이를 통해 메시지를 전달하며 더 이상 커널 호출은 하지 않는다.
-
장점: 커널을 거치지 않아 전달 속도가 빠르고, 커널과 독립된 메모리 공간을 사용해 대량의 메시지 전송에 유리하다.
-
단점: 멀티 프로세스 환경에서 캐시 일관성 문제로 오버헤드가 커 성능 저하가 나타날 수 있다.