프로세스 동기화
프로세스 동기화는 멀티 프로세서 환경에서 다수의 CPU 가 여러 프로세스를 동시에 수행하며 발생하는 동일 데이터 동시 접근 간 발생하는 문제를 해결하기 위한 방법이다.
예를 들어 위와 같이 A 라는 프로세스는 val 라는 값을 1 증가 시키고 B 라는 프로세스도 val 값을 1 증가시키는 기능을 수행한다고 하자.
그렇다면 두 프로세스는 서로 다음과 같은 과정으로 작업을 수행할 것이다.
이 과정에서 만약 val 에 1이라는 값이 저장되어 있고 A 라는 프로세스가 먼저 요청을 수행한다고 가정하자.
그러면 A 는 val 의 현재 값인 1을 읽을 것이고 이후 코드를 실행해 2 라는 값을 메모리에 쓰려 할 것이다.
그런데 메모리에 값을 쓰기 전에 인터럽트가 발생해 B 프로세스로 문맥 교환이 일어나게 되면 아직 변하지 않은 val 값인 1을 B가 읽어 2로 값을 쓴 뒤 다시 A 로 문맥 교환이 되었을때 A 의 PC 는 이미 val 의 데이터를 읽고 더하는 부분을 지나 쓰는 곳 까지 진행되었기 때문에 결과적으로 val 에 2를 쓸 것이고 결국 개발자가 의도한 대로 작업이 이루어지지 않게 된다.
이러한 두 프로세스가 동일한 데이터를 접근해 의도치 않은 동작을 수행하는 것을 Race Condition(경쟁 상태) 라고 하며 이런 공유 데이터를 수정하는 프로세스 코드 부분을 Critical Section(임계 구역) 이라고 한다.
그래서 위 문제를 해결하기 위해 고안된 것이 프로세스 동기화이며 지금부터 프로세스 동기화에 대해 알아보려 한다.
프로세스 동기화의 첫 번째 방법은 공유 데이터에 대해 커널 모드에서 작업 수행 시 다른 프로세스가 선점하지 못하게 하는 것이다. (Data Lock)
해당 정책이 반영될 경우 최소한 위와 같은 상황에서 이미 커널이 데이터를 메모리에 쓰기 위한 시스템 콜을 수행하는 중(이러한 가장 작은 HW 동작을 Atomic Action 이라고 한다) 이라면 다른 프로세스로 문맥 교환 되지 않고 기존 작업을 완전히 수행하기 때문에 어느정도 프로세스 동기화를 기대할 수 있다.
프로세스 동기화의 두 번째 방법은 프로세스들의 임계 구역 간 데이터에 대한 접근 관리이다.
먼저 임계 구역에서 프로세스 동기화를 위해서는 다음 3가지 조건을 만족해야한다.
1. Mutual Exlusion : 어떤 프로세스가 임계 구역을 실행 중일 때 다른 프로세스는 임계 구역을 실행할 수 없다.
2. Progress : 임계 구역을 진행하는 프로세스가 없을 경우 어떠한 프로세스라도 들어가야한다.
3. Bounded Waiting : 어떤 프로세스든 임계 구역 대기시간은 유한 해야한다.
따라서 멀티 프로세서 환경에서 임계 구역 코드는 위의 조건들을 만족해야하며 이를 구현하기 위해 피터슨 알고리즘이 고안되었다.
하지만 매번 모든 개발자가 위의 조건을 따져가며 코드를 설계하기가 현실적으로 힘들기 때문에 보다 쉽게 프로세스 동기화를 할 수 있게 제공되는 추상 자료형이 바로 세마포어(Semaphore) 다.
세마포어는 임계 구역에 프로세스가 접근하기 위한 구분자로 정수형 자료형이며 단순 사용여부만 따지는 1 or 0 인 Binary Semaphore = Mutext, 그리고 단순 사용여부 뿐만 아니라 현재 임계 구역에 접근 가능한 프로세스의 갯수를 표현하는 Counting Semaphore = Ordinary Semaphore 로 나뉘며 다음과 같은 두 가지 프로세스 동기화에 사용된다.
하지만 개발자가 세마포어를 사용할지라도 설계가 잘못된다면 오히려 두 프로세스가 서로 임계 구역에 접근하지 못하는 교착상태에 빠지게 되며 이를 Dead Lock 이라고 한다.
다음 시간에는 프로세스 동기화 간 유명한 예시들을 몇 가지 살펴보며 어떠한 부분에 주의하며 세마포어를 사용해야하는지 알아보려고 한다.