운영체제 시간에 세마포어와 뮤텍스를 들어보기만 했지 무엇인지 잘 몰랐는데 운영체제 관련한 면접 질문 중에 단골 질문이여서 이번엔 "세마포어와 뮤텍스의 차이"를 알아보려고 한다. 근데 피피티로 발표했을 때랑 예시가 다르다는 점!
세마포어와 뮤텍스를 알아보고 이것들의 차이를 알아보기 전에 프로세스 동기화에 대해서 조금 알아볼 것이다.
프로세스 동기화?
프로세스는 서로 메세지를 보내고 프로세스 내부에서는 스레드끼리 자원을 공유하면서 동기화에 대한 문제가 항상 발생할 수 있다.
오늘 알아볼 세마포어와 뮤텍스는 프로세스 동기화 기법 중 하나인데 여러 프로세스나 스레드가 공유자원에 접근하는 것을 제어하기 위한 방법이라고 할 수 있다.
여기 공중화장실이 있다
화장실 칸마다 자물쇠로 잠겨져있고 그 칸을 들어가기 위해선 열쇠가 필요하다고 생각해보자. 화장실 칸 수가 1개이면 열쇠도 1개가 되고 화장실 칸 수가 4개일때도 열쇠가 4개로 세마포어 수가 처음에 설정이 됩니다.
화장실 칸 마다 사람이 들어오게되면 들어갈 수 있는 화장실의 칸이 적어지게 되고 만약 화장실이 만원이 된다면 칸 수도 0개, 열쇠도 0개이다.
근데 볼일을 본 사람이 화장실을 나왔다면 화장실 칸 수가 1이 증가하고 열쇠도 1개 증가한다. 그리고 대기하고 있던 사람에게 넘겨주게 되는데
정리를 해보자면
화장실은 공유자원이었고, 사람이 스레드, 프로세스이고, 화장실의 빈칸의 수는 현재 공유자원에 접근할 수 있는 스레드, 프로세스의 개수를 의미한다는 것을 참고하면 좋을 것 같다. 그래서 세마포어는 공통으로 관리하는 하나의값을 이용해 상호배제를 달성한다.
아까랑 똑같이 화장실을 예시로 들어봅시다. 여러 화장실 칸을 가질 수 있는 세마포어와는 다르게 뮤텍스는 칸이 하나밖에 없는 화장실이랑 비슷하다.
화장실을 가기위해 열쇠가 필요하다. 만약 당신이 화장실에서 볼일을 보고있는데 뒤에 절친이 배에서 신호가 왔다. 하지만 절친은 열쇠가 없기때문에 아무리 신호가 아프다고해도 절친은 당신이 볼일을 다 보고 나온 후에야 화장실을 들어갈 수 있는 것이다.
뮤텍스는 이렇게 설명한 것처럼 돌아가게 되는데 여기서도 마찬가지로 사람은 프로세스 혹은 스레드이고 화장실은 공유자원, 열쇠는 공유자원에 접근하기 위해 필요한 어떤 오브젝트이다. 그리고 공유 자원을 점유한 프로세스는 락(lock)을 지니며 자원 사용을 마치면 락을 반납한다.
정리를 해보자면
뮤텍스는 열쇠에 해당하는 어떤 오브젝트가 있으며 이 오브젝트를 소유한 스레드 혹은 프로세스만이 공유자원에 접근할 수 있다.
typedef struct {
int value;
struct process *list;
} Semaphore;
// P
void Wait(Semaphore *S) {
S->value--;
if (S->value < 0) {
/* S->list로 push*/
Block();
}
}
// V
void Signal(Semaphore *S) {
S->value++;
if (S->value <= 0) {
/* S->list에 pop */
WakeUp(P);
}
}
// Semaphore implementation
do {
Wait(&S);
Signal(&S);
} while (true);
출처: https://rebas.kr/857 [PROJECT REBAS]
// P and V
wait(S) {
while (S <= 0);
S--;
}
signal(S) {
S++;
}
// Mutex implementation in binary semaphore
do {
wait(&mutex);
signal(&mutex);
} while (true);
출처: https://rebas.kr/857 [PROJECT REBAS]
세마포어는 뮤텍스가 될 수 있지만 뮤텍스는 세마포어가 될 수 없다.
세마포어는 소요할 수 없는 반면 뮤텍스는 소유가 가능하며 소유주가 이에 대한 책임을 진다
뮤텍스의 경우 뮤텍스를 소유하고 있는 스레드가 이 뮤텍스를 해제할 수 있다. 하지만 세마포어의 경우 이러한 세마포어를 소유하지 않는 스레드가 세마포어를 해제할 수 있다.
세마포어는 시스템 범위에 걸쳐있고 파일시스템상의 파일 형태로 존재한다. 뮤텍스는 프로세스 범위를 가지며 프로세스가 종료될 때 자동으로 clean up된다.
가장 큰 차이는 동기화 대상의 갯수~!