
동기화란
동기화의 의미
동시다발적으로 실행되는 많은 프로세스는 서로 데이터를 주고받으며 협력하며 실행됩니다. 이렇게 협력적으로 실행되는 프로세스들은 아무렇게나 마구 동시에 실행해서는 안 됩니다. 올바른 실행을 위해서는 동기화가 필수입니다.
프로세스 동기화란 프로세스들 사이의 수행 시기를 맞추는 것을 의미합니다. 프로세스들 사이의 수행 시기를 맞추는 것은 무엇을 의미할까요? 크게 아래 두 가지를 일컫습니다.
즉 동기화에는 실행 순서 제어를 위한 동기화가 있고, 상호 배제를 위한 동기화가 있습니다.
첫째, 실행 순서 제어를 위한 동기화에 대해 알아봅시다.
가령 하나의 book.txt 파일을 제어하는 writer, reader 프로세스가 있다고 해봅시다. 이 두 프로세스는 무작정 실행되면 안됩니다. reader 프로세스는 writer 프로세스가 끝나야 실행할 수 있기 때문입니다.
이렇게 동시에 실행되는 프로세스를 올바른 순서대로 실행하는 것이 첫 번째 프로세스 동기화 입니다.
둘째, 상호 배제를 위한 동기화에 대해서도 알아봅시다.
상호 배제는 공유가 불가능한 자원의 동시 사용을 피하기 위해 사용하는 알고리즘 입니다.
계좌에 10만원이 있는데 2만원을 넣는 프로세스A와 5만원을 넣는 프로세스B가 있다고 가정해봅시다. 만일 A,B가 동시에 실행된다면 A는 10만원을 기준으로 2만원이 추가되므로 12만원이 될 것이고, B는 10만원을 기준으로 5만원이 추가되므로 15만원이 될 것입니다.
그래서 최종적으론 15만원이 계좌에 남을것입니다. 이렇게 동시에 접근해서는 안되는 자원에 동시에 접근하지 못하게 하는 것이 상호 배제를 위한 동기화 입니다.
공유 자원과 임계 구역
동시에 실행되는 프로세스들은 공동의 자원을 두고 작업을 합니다.이런 자원을 공유 자원이라고 합니다. 공유자원은 전역 변수가 될 수도 있고, 파일이 될 수도 있고, 입출력장치가 될 수도 있습니다.
그리고 이 공유 자원 중에는 두 개 이상의 프로세스를 동시에 실행하면 문제가 발생하는 자원이 있습니다. 이렇게 동시에 실행하면 문제가 발생하는 자원에 접근하는 코드 영역을 임계 구역이라고 합니다.
두 개 이상의 프로세스가 임계 구역에 진입하고자 하면 둘 중 하나는 대기해야 합니다. 임계 구역에 먼저 진입한 프로세스의 작업이 마무리되면 그제서야 비로소 기다렸던 프로세스가 임계 구역에 진입합니다.
임계 구역은 두 개 이상의 프로세스가 동시에 실행되면 안 되는 영역이지만, 잘못된 실행으로 인해 여러 프로세스가 동시 다발적으로 임계 구역의 코드를 실행하여 문제가 발생하는 경우가 있습니다. 이를 레이스 컨디션이라고 합니다.
상호 배제를 위한 동기화는 이와 같은 일이 발생하지 않도록 두 개 이상의 프로세스가 임계 구역에 동시에 접근하지 못하도록 관리하는 것을 의미합니다.
운영체제는 이러한 임계 구역 문제를 아래 세 가지 원칙 하에 해결합니다.
동기화 기법
프로세스 동기화는 어떻게 이루어질까요? 어떻게 해야 임계 구역에 오직 하나의 프로세스만 진입하게 하고, 올바른 실행 순서를 보장할 수 있을까요? 이를 위해 동기화를 위한 대표적인 도구인 뮤텍스 락, 세마포, 모니터를 학습해 보겠습니다.
뮤텍스 락
뮤텍스 락은 동시에 접근해서는 안되는 자원에 동시에 접근하지 않도록 만드는 도구, 다시 말해 상호 배제를 위한 동기화 도구입니다.
임계 구역에 진입하는 프로세스는 '내가 임계 구역에 있음'을 알리기 위해 뮤텍스 락을 이용해 임계 구역에 자물쇠를 걸어둘 수 있습니다.
뮤텍스 락의 매우 단순한 형태는 하나의 전역 변수와 두 개의 함수로 구현할 수 있습니다.
acquire 함수는 프로세스가 임계 구역에 진입하기 전에 호출하는 함수입니다. 만일 임계 구역이 잠겨 있다면 임계 구역이 열릴 때까지 임계 구역을 반복적으로 확인하고, 임계 구역이 열려있다면 임계 구역을 잠그는 함수입니다.
release 함수는 임계 구역에서의 작업이 끝나고 호출하는 함수입니다. 현재 잠긴 임계 구역을 열어주는 함수라고 보면 됩니다.
acquire와 release 함수를 임계 구역 전후로 호출함으로써 하나의 프로세스만 임계 구역에 진입할 수 있습니다.
이렇게 되면 프로세스는
세마포
세마포는 뮤텍스 락과 비슷하지만, 조금 더 일반화된 방식의 동기화 도구입니다. 뮤텍스 락은 하나의 공유 자원에 접근하는 프로세스를 상정한 방식입니다. 하지만 공유 자원이 여러 개 있을 경우 여러개의 프로세스가 각각 공유 자원에 접근이 가능해야 합니다.
이처럼 세마포는 공유 자원이 여러 개 있는 상황에서도 적용이 가능한 동기화 도구입니다.
세마포가 어떻게 구현되는지 간략하게 살펴보겠습니다. 세마포는 뮤텍스 락과 비슷하게 하나의 변수와 두 개의 함수로 단순하게 구현할 수 있습니다.
세마포에서 공유 자원이 없는 경우 프로세스는 무작정 무한히 반복되며 S를 확인하게 됩니다. 이렇게 바쁜 대기를 반복하며 확인할 시간에 CPU는 더 생산성 있는 작업을 할 수 있을텐데, CPU 주기를 낭비한다는 점에서 손해입니다.
그래서 실제로 세마포는 다른 더 좋은 방법을 사용합니다. wait 함수는 만일 사용할 수 있는 자원이 없을 경우 해당 프로세스 상태를 대기 상태로 만들고, 그 프로세스의 PCB를 세마포를 위한 대기 큐에 집어넣습니다. 그리고 다른 프로세스가 임계 구역에서의 작업이 끝나고 signal 함수를 호출하면 signal 함수는 대기 중인 프로세스를 대기 큐에서 제거하고, 프로세스 상태를 준비 상태로 변경한 뒤 준비 큐로 옮겨줍니다.
모니터
세마포는 훌륭한 프로세스 동기화 도구이지만, 사용하기에 불편함이 있습니다. 매번 임계구역 앞뒤로 wait와 signal 함수를 명시하는 것은 번거롭기 때문입니다.
이에 최근 등장한 동기화 도구가 모니터 입니다. 모니터는 공유 자원과 공유 자원에 접근하기 위한 인터페이스를 묶어 관리합니다. 그리고 프로세스는 반드시 인터페이스를 통해서만 공유 자원에 접근하도록 합니다.
모니터를 통해 공유 자원에 접근하려는 프로세스를 큐에 삽입하고, 큐에 삽입된 순서대로 하나씩 공유 자원을 이용하도록 합니다. 즉 모니터는 공유 자원을 다루는 인터페이스에 접근하기 위한 큐를 만들고, 모니터 안에 항상 하나의 프로세스만 들어오도록 하여 상호 배제를 위한 동기화를 제공합니다.
모니터는 세마포와 마찬가지로 실행 순서 제어를 위한 동기화도 제공합니다. 특정 조건을 바탕으로 프로세스를 실행하고 일시 중단하기 위해 모니터는 조건 변수를 사용하는데, 조건 변수는 프로세스나 스레드의 실행 순서를 제어하기 위해 사용하는 특별한 변수입니다.
조건 변수로는 wait와 signal 연산을 수행할 수 있습니다. 우선 wait는 호출한 프로세스의 상태를 대기 상태로 전환하고 일시적으로 조건 변수에 대한 대기 큐에 삽입하는 연산입니다. 여기서 헷갈리면 안되는 점은 모니터에 진입하기 위해 삽입되는 큐와 wait가 호출되어 실행이 중단된 프로세스들이 삽입되는 큐는 다르다는 점입니다.
wait 연산으로 일시 중지된 프로세스는 다른 프로세스의 signal 연산을 통해 실행이 재개될 수 있습니다. 즉, signal은 wait를 호출하여 큐에 삽입된 프로세스의 실행을 재개하는 연산입니다.
