on
쉽게 설명하는 뮤텍스(Mutex)와 세마포어(Semaphore)!
쉽게 설명하는 뮤텍스(Mutex)와 세마포어(Semaphore)!
반응형
뮤텍스와 세마포어를 알아보기 이전에는 교착 상태에 대한 이해가 선행되어야 한다.
(교착상태를 모르는 사람은 아래의 교착상태 글을 먼저 읽어보길 추천합니다!)
https://suzyalrahala.tistory.com/59
Semaphore란 무엇일까?
세마포어는 동기화를 위해 만들어진 소프트웨어이다. 프로세스들이 모두 꽉 차있으면 막고 대기표를 주고, 진행중이던 프로세스가 끝나면 대기하던 프로세스를 실행시켜준다. 초기에 P, V로 사용되었으며 P는 test이며, V는 increment이다. (왜 세마포어라는 이름일까 찾아보니 역이나 군대에서 사용하던 수신호였다고 한다.)
class Semaphore { int value; // number of permits Semaphore(int value) { // ... } void acquire() { value--; if (value < 0) { // add this process/thread to list // block } } void release() { value++; if (value <= 0) { // remove a process P from list // wakeup P } } }
value는 권한의 갯수이다.
acquire()는 value값을 감소시키고 만약 value값이 0보다 작으면 이미 그 임계구역에 프로세스가 존재한다는 의미이므로 현재 프로세스는 접근하지 못하도록 막아준다. 그리고 list 대기줄에 추가한 뒤 실행되지 못하도록 block을 건다.
release()는 value의 값을 증가시키고, 만약 value가 0보다 같거나 작으면 임계구역에 진입하려고 대기하는 프로세스가 list에 남아있다는 의미이므로 그 중에서 하나를 꺼내어 임계구역을 수행할 수 있도록 한다.
이처럼 세마포어는 상호 배제를 위해 일반적으로 사용된다.
상호배제란?
하나의 프로세스가 공유자원을 사용할 때 다른 프로세스가 동일한 공유자원에 접근할 수 없도록 하는것이다.
세마포어를 도식화 시켜서 매커니즘의 실행 순서를 제대로 알아보자.
위의 코드를 전체 구조 도식화를 하면 이렇게 된다.
A, B 두개의 스레드가 있다고 하자. (value의 초기값은 1로 셋팅)
1. 스레드 A가 먼저 실행이 된다면 acquire()가 실행되고 value는 0이 된다.
2. 0보다 작지 않기에 acquire()내부 if문을 만족하지 않고 block 되지 않는다. 트랜젝션이 실행된다.
3. 트랜젝션을 update 하는 중 context switching이 발생하여 스레드 B가 돈다.
4. B는 acquire()을 실행하고 value는 -1이 된다.
5. 내부 if문을 만족했기에 block처리 되고, Queue에 갇힌다.
6. 다시 순서가 돌아와서 스레드 A가 실행이 되고 release()를 호출해 value는 다시 0이 된다.
7. +1을 했음에도 0이 되었다는 것은 Queue에 대기중인 프로세스가 있다는 뜻이기에 B를 다시 Ready Queue로 보내고 cpu에 의해 실행되기를 기다리다 동일하게 순차적으로 실행이 된다.
이처럼 상호배제를 위해서 쓰이기도 하지만 세마포어는 프로세스의 실행 순서를 원하는 순서로 설정해주기도 한다.
P1이 먼저 실행된다면?
Section1이전에 아무런 동작이 없으므로 수행되고 바로 relase()로 넘어간다.
release는 value를 1 증가 시키고 대기 리스트에 있는 프로세스를 깨워주지만 아무런 프로세스가 없으므로 동작하지 않는다.
P2가 실행되고 현재 value는 1이기에 이를 감소시키면 0이 된다. 0이면 block되지 않기에 Section2가 수행된다.
P2가 먼저 실행된다면?
acquire()이 실행되고 value가 1감소하면 -1이 된다.
그러므로 block 처리되고 Section2는 세마포어 큐(대기)에 삽입된다.
P1이 실행되면 바로 Section1이 수행되고 release()가 실행된다.
현재 value가 -1이기에 세마포어 큐에 있는 대기중인 프로세스를 깨워준다. Section2가 수행된다.
이처럼 P1이 먼저 실행되건, P2가 먼저 실행되건 프로세스의 수행 순서는 무조건 P1->P2로 만들고자 할 때 세마포어를 써줄 수 있다.
그렇다면 뮤텍스란 무엇일까?
Mutual 와 Exclusion의 합성어로서 여러 스레드를 실행하는 환경에서 자원에 대한 접근에 제한을 강제하기 위한 동기화 매커니즘이다. 즉, 뮤텍스도 세마포어와 같이 병행처리를 할 수 있는 동기화 기법인 것. 작동 방식은 임계영역에 들어갈 때 lock(락)을 걸고 다른 프로세스가 접근하지 못하도로고 막고, 임계영역에서 나올 때 그 lock을 해제한다.
mutex = 1; void lock () { while (mutex != 1) { /* mutex 값이 1이 될 때까지 기다립니다.*/ } /* 이 구역에 도착했다는 것은 mutex 값이 1이라는 것입니다. 따라서 이제 뮤텍스 값을 0으로 만들어 다른 프로세스(혹은 쓰레드)가 접근하지 못하도록 막아야 합니다. */ mutex = 0; } void unlock() { /* 임계 구역에서 나온 프로세스는 다른 프로세스가 접근할 수 있도록 락을 해제합니다.*/ mutex = 1; }
뮤텍스는 세마포어와 다르게 오직 하나의 스레드만이 임계영역에 들어올 수 있다는 차이가 있다. 세마포어는 변수만큼의 프로세스가 접근 가능하고 다른 프로세스가 세마포어를 해제해줄 수 있었지만, 뮤텍스는 1개의 lock만을 가지고 해당 스레드만이 임계영역에서 나갈 때 뮤텍스를 해제할 수 있도록 만들어져서 하나의 스레드만 임계영역에 들어갈 수 있다.
참고 문헌:
https://gona.tistory.com/71#comment13528023
반응형
from http://suzyalrahala.tistory.com/61 by ccl(A) rewrite - 2021-12-11 12:01:19