프로세스 동기화란 작업들 사이의 수행 시기를 맞추는 것
다시 말해 프로세스들 사이의 수행 시기를 맞추는 것을 의미한다.
동기화에는 실행 순서 제어를 위한 동기화가 있고, 상호 배제를 위한 동기화가 있다.
실행 순서 제어: 프로세스를 올바른 순서대로 실행하기
상호 배제: 동시에 접근해서는 안되는 자원에 하나의 프로세스만 접근하게 하기
ex) Writer와 Reader 프로세스가 동시에 실행 중이라고 가정해보자. 이때 Writer 프로세스는 Book.txt파일에 값을 저장하는 프로세스이고, Reader 프로세스는 Book.txt파일에 저장된 값을 읽어들이는 프로세스라고 해보자.
Writer 프로세스와 Reader 프로세스는 아무 순서대로 실행되어서는 안된다. Reader 프로세스는 Writer 프로세스의 실행이 끝나야만 실행할 수 있다. 다시 말해 Reader 프로세스는 "Book.txt 안에 값이 존재한다"는 조건이 만족되어야만 실행을 이어나갈 수 있다.
이렇게 동시에 실행되는 프로세스를 올바른 순서대로 실행하는 것이 프로세스 동기화이다.
ex) 10만원이 저축되어 있는 계좌가 있다고 가정해보자. 프로세스 A는 이 계좌에 2만원을 입금하는 프로세스, 프로세스 B는 이 계좌에 5만원을 넣는 프로세스라고 해보자.
프로세스 A가 실행되는 과정을 살펴보면
1) 계좌의 잔액을 읽는다.
2) 읽은 잔액에 2만원을 더한다.
3) 더한 값을 저장한다.
마찬가지로 프로세스 B가 실행되는 과정은
1) 계좌의 잔액을 읽는다.
2) 읽은 잔액에 5만원을 더한다.
3) 더한 값을 저장한다.
만약 프로세스 A와 B를 동시에 실행할 때 동기화가 이루어지지 않는다면 예상하지 못한 값이 계좌에 저장될 것이다.
A의 작업이 끝나기도 전에 B가 잔액을 읽어버렸기 때문에 엉뚱한 결과가 나온다. 올바른 결과를 위해서는 A가 잔액에 접근했을 때 B는 A의 작업이 끝날 때 까지 기다려야 한다.
상호 배제의 예시에서 보았듯 프로세스들이 동시에 접근해서는 안되는 자원 또는 영역이 존재한다.
여러 프로세스들이 공동으로 이용하는 자원(변수, 파일, 장치)을 공유 자원이라고 한다.
공유 자원에 접근하는 코드 중 동시에 실행하면 문제가 발생하는 코드 영역을 임계 구역이라고 한다.
여러 프로세스가 동시에 임계 구역의 코드를 실행하여 발생하는 문제
프로세스 A와 B가 각각 계좌에 잔액을 더했지만 엉뚱한 결과가 나온 문제를 Race Condition의 사례로 볼 수 있다.
운영체제는 임계 구역 문제를 해결하기 위해 3가지 원칙을 사용한다.
상호 배제(동시 접근을 막기 위한)를 위한 동기화 도구
뮤텍스 락을 통해 임계 구역에 락을 걸어둘 수 있다.
락을 획득할 수 없다면 락을 획득할 수 있을 때까지 락을 확인(바쁜 대기)
락을 획득할 수 있다면 임계 구역을 잠근 뒤, 임계 구역에서의 작업을 진행
임계 구역에서 나올 때에는 다시 락을 해제
바쁜 대기로 인해 CPU 리소스를 낭비할 우려가 있다.
공유 자원이 여러 개 있는 상황에서도 적용 가능한 동기화 도구
세마포를 이용하면 동시에 실행되는 프로세스 혹은 스레드 간에 상호 배제를 위한 동기화와 실행 순서 제어를 위한 동기화를 할 수 있다.
세마포는 멈춤 신호와 가도 좋다는 신호로 임계 구역을 관리한다.
멈춤 신호를 받은 프로세스는 잠시 기다리고, 가도 좋다 신호를 받으면 임계 구역에 진입한다.
임계 구역에 진입할 수 있는 프로세스의 개수를 전역 변수 S, 멈춤 신호를 wait(), 가도 좋다 신호를 signal()로 표현할 수 있다.
세마포는 바쁜 대기를 방지하기 위해 기다리는 프로세스를 대기 상태로 만들고, 그 프로세스의 PCB를 세마포를 위한 대기 큐에 넣는다.
다른 프로세스가 임계 구역에서의 작업이 끝나 signal()을 대기 큐에서 프로세스를 제거하고, 프로세스의 상태를 준비 상태로 변경하여 프로세스를 준비 큐로 옮긴다.
공유자원과 공유자원에 접근하기 위한 인터페이스를 묶어서 관리하는 동기화 도구
프로세스는 반드시 인터페이스를 통해서만 공유 자원에 접근할 수 있다.
모니터는 모니터에 진입하기 위한 큐를 만들고, 모니터안에 항상 하나의 프로세스만 들어오도록 하여 상호 배제를 위한 동기화를 제공한다.
모니터는 조건 변수를 바탕으로 프로세스를 실행하고, 일시 중단하며 실행 순서 제어를 위한 동기화를 제공한다.
조건 변수로 wait()와 signal() 연산을 수행할 수 있다.