Search

12-2 동기화 기법(뮤테스 락, 세마포, 모니터)

Last update: @1/7/2023
혼자 공부하는 컴퓨터구조 + 운영체제

운영체제

09 운영체제 시작하기

10 프로세스와 스레드

11 CPU 스케줄링

12 프로세스 동기화

13 교착 상태

14 가상 메모리

15 파일 시스템

뮤테스 락(Mutex lock; MUTual EXclusion lock) : 어떤 자원을 사용하는 임계구역에 들어갈 때 다른 프로세스가 접근하지 못하도록 자물쇠로 잠그는 기능을 코드로 구현한 것
뮤테스 락의 가장 단순한 형태는 하나의 전역 변수와 두 개의 함수로 구현할 수 있음
전역변수 lock : 프로세스들이 공유
acquire 함수 : 임계 구역을 잠그는 역할
프로세스가 임계 구역에 진입하기 전에 호출하는 함수
만약 임계 구역이 잠겨 있다면 임계 구역이 열릴 때까지(lock이 false가 될 때까지) 임계 구역을 반복적으로 확인
임계 구역에 열려 있다면 임계 구역을 잠그는 역할(lock을 true로 바꿈)
acquire() { while (lock == true) { } // 임계 구역이 잠겨 있는지 반복적으로 확인 lock = true; // 만약 임계 구역이 잠겨 있지 않다면 임계 구역 잠금 }
Java
복사
release 함수 : 임계 구역의 잠금을 해제하는 역할
임계 구역에서의 작업이 끝나고 호출하는 함수
현재 잠긴 임계 구역을 열어주는(lock을 false로 바꾸는) 함수
release() { lock = false; // 임계 구역 작업이 끝났으면 잠금 해제 }
Java
복사
즉, 프로세스는 위 함수들을 아래처럼 호출하여 임계구역 작업을 진행함
acquire(); // 임계 구역 작업 release();
Java
복사
이렇게 되면 만약 락이 걸려있을 경우 락이 풀려있는 것을 반복적으로 확인함(while문). 이런 대기방식을 바쁜 대기(busy wait)라고 함
C/C++, python 등 일부 언어에서는 사용자가 직접 위 함수들을 구현하지 않도록 뮤텍스 락 기능을 제공함
세마포(semaphore, 직역하면 수기신호(손에 깃발을 들고 하는 신호)) : 뮤텍스 락과 비슷하지만, 공유 자원이 여러 개 있는 상황에서도 적용이 가능한 동기화 도구
이진 세마포(binary semaphore), 카운팅 세마포(counting semaphore)가 있는데, 이진 세마포는 뮤텍스 락과 비슷한 개념이고, 여기서는 카운팅 세마포를 다룸
네덜란드의 컴퓨터과학자 에츠허르 다익스트라(Edsger W.Dijkstra)에 의해 개발됨
세마포는 ‘멈춤’ 신호와 ‘가도 좋다’는 신호로서 임계 구역을 관리함. 즉, 프로세스는 임계 구역 앞에서 멈춤 신호를 받으면 잠시 기다리고, 가도 좋다는 신호를 받으면 그제서야 임계 구역에 들어가게 됨
세마포는 하나의 변수와 두 개의 함수로 단순하게 구현할 수 있음
전역 변수 S :임계 구역에 진입할 수 있는 프로세스의 개수(사용 가능한 공유 자원의 개수)를 나타내는 변수
wait 함수 : 임계 구역에 들어가도 좋은지, 기다려야 할지를 알려주는 함수
변수 S는 임계 구역에 진입할 수 있는 프로세스의 개수, 혹은 사용 가능한 공유 자원의 개수임을 토대로 생각해 보았을 때 wait 함수는 아래와 같이 만듦
wait() { while( s <= 0 ) { // 임계 구역에 진입할 수 있는 프로세스 개수가 0 이하라면 // 사용할 수 있는 자원이 있는지 반복적으로 확인 } S--; // 임계 구역에 진입할 수 있는 프로세스 개수가 하나 이상이면 S를 1 감소시키고 임계 구역 진입 }
Java
복사
signal 함수 : 임계 구역 앞에서 기다리는 프로세스에 ‘이제 가도 좋다’고 신호를 주는 함수
signal() { S++; // 임계 구역에서의 작업을 마친 뒤 S를 1 증가시킴 }
Java
복사
세마포도 임계구역 진입 전후로 wait()와 signal()을 호출함
wait() // 임계 구역 signal()
Java
복사
세마포에서는 사용할 수 있는 자원이 없을 경우 busy wait를 시키지 않고 프로세스를 대기상태로 만들고 그 프로세스의 PCB를 세마포를 위한 대기 큐에 집어넣음
그리고 다른 프로세스가 임계 구역 작업을 끝내고 signal 함수를 호출하면 signal 함수는 대기 중인 프로세스를 대기 큐에서 제거하고, 준비 상태로 변경한 뒤 준비 큐로 옮겨줌
wait() { S--; if ( S < 0 ) { add this process to Queue; // 해당 프로세스 PCB를 대기 큐에 삽입 sleep(); // 대기 상태로 접어듦 } }
Java
복사
signal() { S++; if ( S <= 0 ) { remove a process p from Queue // 대기 큐에 있는 프로세스 p를 제거 wakeup(p) // 프로세스 p를 대기 상태에서 준비 상태로 만듦 } }
Java
복사
1.
프로세스 P1 wait 호출. S를 1 감소시키면 S는 1이므로 임계 구역 진입
2.
프로세스 P2 wait 호출. S를 1 감소시키면 S는 0이므로 임계 구역 진입
3.
프로세스 P3 wait 호출. S를 1 감소시키면 S는 -1이므로 본인의 PCB를 대기 큐에 넣고 대기 상태로 전환
4.
프로세스 P1 임계 구역 작업 종료, signal() 호출. S를 1 증가하면 0이므로 대기 상태였던 P3 를 대기 큐에서 꺼내 준비 큐로 옮겨줌
5.
깨어난 프로세스 P3 임계 구역 진입
6.
프로세스 P2 임계 구역 작업 종료, signal() 호출. S가 1 증가하면 1
7.
프로세스 P3 임계 구역 작업 종료, signal() 호출. S가 1 증가하면 2
위는 동시에 접근해서는 안되는 자원에 동시에 접근하지 않도록 제어하는 상호 배제를 위한 동기화에 대해당
특정 조건이 만족되어야만 실행할수 있는 상황에서 올바른 순서대로 실행하게 하는 실행 순서 제어를 위한 동기화도 세마포로 할 수 있음
방법은 간단한데, 세마포의 변수 S를 0으로 두고 먼저 실행할 프로세스 뒤에 signal 함수, 다음에 실행할 프로세스 앞에 wait 함수를 붙이면 됨
이 경우, P1이 먼저 실행되면 P1이 임계 구역에 먼저 진입하는 것은 자명한 일이고, P2가 먼저 실행되더라도 P2는 wait 함수를 만나므로 P1이 임계 구역에 진입함
그리고 P1이 임계 구역의 실행을 끝내고 signal을 호출하면 그제서야 P2가 임계 구역에 진입함
즉, P1이 먼저 실행되든P2가 먼저 실행되든 반드시 P1, P2 순서대로 실행됨
단점
매번 임계 구역에 앞뒤로 일일이 wait와 signal 함수를 명시하는 것은 번거로움
더군다나 자칫 아래처럼 잘못된 코드로 인해 예기치 못한 결과를 얻을 수도 있음
모니터(monitor) : 최근에 등장한 동기화 도구로, 세마포에 비해 사용자가 사용하기에 훨씬 편리함
모니터는 공유 자원과 공유 자원에 접근하기 위한 인터페이스(통로)를 묶어 관리함
프로세스는 반드시 인터페이스를 통해서만 공유 자원에 접근하도록 함
이를 위해 모니터를 통해 공유 자원에 접근하고자 하는 프로세스를 큐에 삽입하고, 큐에 삽입된 순서 대로 하나씩 공유 자원을 이용하도록 함
즉, 모니터는 공유 자원을 다루는 인터페이스에 접근하기 위한 큐(모니터에 진입하기 위한 큐)를 만들고, 모니터 안에 항상 하나의 프로세스만 들어오도록 하여 상호 배제를 위한 동기화를 제공함
모니터는 세마포와 마찬가지로 실행 순서 제어를 위한 동기화도 제공함
특정 조건을 바탕으로 프로세스를 실행하고 일시 중단하기 위해 모니터는 조건 변수(condition variable)를 사용함
조건 변수는 프로세스나 스레드의 실행 순서를 제어하기 위해 사용하는 특별한 변수임
모니터가 조건 변수를 사용하기는 하지만 조건 변수와 모니터와는 별개의 개념임
조건 변수로는 wait와 signal 연산을 수행할 수 있음
wait는 호출한 프로세스의 상태를 대기 상태로 전환하고 일시적으로 조건 변수에 대한 대기 큐에 삽입하는 연산
여기서 헷갈리면 안 되는 점은 모니터에 진입하기 위해 삽입되는 큐(상호 배제를 위한 큐)와 wait가 호출되어 실행이 중단된 프로세스들이 삽입되는 큐(조건 변수에 대한 큐)는 다르다는 점임
전자는 모니터에한 번에 하나의 프로세스만 진입하도록 하기 위해 만들어진 큐
후자는 모니터에 이미 진입한 프로세스의 실행 조건이 만족될 때까지 잠시 실행이 중단되어 기다리기 위해 만들어진 큐
모니터에 진입한 어떤 프로세스가 x.wait( )를 통해 조건 변수 x에 대한 wait를 호출했다고 가정
그 프로세스는 다음 그림처럼 조건 변수 x에 대한 큐에 삽입되므로 모니터는 다시 비게 되고, 그렇기에 다른 프로세스가 모니터 안에 들어올 수 있는 것임
x.wait() 연산으로 일시 중지된 프로세스는 다른 프로세스의 x.signal() 연산을 통해 실행이 재개될 수 있음
모니터 안에는 하나의 프로세스만이 있을 수 있기 때문에 wait를 호출했던 프로세스는signal을 호출한 프로세스가 모니터를 떠난 뒤에 실행되거나, signal을 호출한 프로세스의 실행을일시 중단하고 자신이 실행된 뒤 다시 signal을 호출한 프로세스의 수행을 재개함
중요한 점은 모니터는 조건 변수를 이용하여 아래와 같은 프로세스 실행 순서 제어를 위한 동기화를 제공한다는 사실임
1.
특정 프로세스가 아직 실행될 조건이 되지 않았을 때에는 wait를 통해 실행을 중단함
2.
특정 프로세스가 실행될 조건이 충족되었을 때에는 signal을 통해 실행을 재개함