뮤텍스(Mutex) & 세마포어(Semaphore)

[공룡책 정리] 뮤텍스와 세마포어: Chapter 6. Synchronization Tools

세마포어(Semaphore) & 뮤텍스(Mutex) 공유된 자원에 여러 프로세스가 동시에 접근하면서 문제가 발생할 수 있다. 이때 공유된 자원의 데이터는 한 번에 하나의 프로세스만 접근할 수 있도록 제한을 둬야 한다. 이를 위해 나온 것이 바로 ‘세마포어’ 와 ‘뮤텍스’

세마포어(Semaphore) : 공유된 자원의 데이터 혹은 임계영역(Critical Section) 등에 여러 Process 혹은 Thread가 접근하는 것을 막아줌(즉, 동기화 대상이 하나 이상)

세마포어P(Proberen), V(Verhogen) 연산 P : 임계 구역 들어가기 전에 수행( 프로세스 진입 여부를 자원의 개수(S)를 통해 결정) V : 임계 구역에서 나올 때 수행( 자원 반납 알림, 대기 중인 프로세스를 깨우는 신호) 구현 방법 procedureP(S) –> 최초S값은1임 whileS=0 dowait –> S가0면1이 될때까지 기다려야 함 S :=S-1 –> S를0로 만들어 다른 프로세스가 들어 오지 못하도록 함 endP — 임계 구역— procedureV(S) –> 현재상태는S가0임 S :=S+1 –> S를1로 원위치시켜 해제하는 과정 endV 이를 통해, 한 프로세스가P 혹은V를 수행하고 있는 동안 프로세스가 인터럽트 당하지 않게 된다. P와V를 사용하여 임계 구역에 대한 상호배제 구현이 가능하게 되었다. 예시 최초S 값은1이고, 현재 해당 구역을 수행할 프로세스A, B가 있다고 가정하자

  1. 먼저 도착한A가P(S)를 실행하여S를0으로 만들고 임계구역에 들어감
  2. 그 뒤에 도착한B가P(S)를 실행하지만S가0이므로 대기 상태
  3. A가 임계구역 수행을 마치고V(S)를 실행하면S는 다시1이 됨
  4. B는 이제P(S)에서while문을 빠져나올 수 있고, 임계구역으로 들어가 수행함
  • 뮤텍스(Mutex) : 공유된 자원의 데이터 혹은 임계영역(Critical Section) 등에 하나의 Process 혹은 Thread가 접근하는 것을 막아줌(즉, 동기화 대상이 하나)

상호 배제(Mutual Exclusion)의 약자임 해당 접근을 조율하기 위해lock과unlock을 사용한다. • Acquire lock : 현재 임계 구역에 들어갈 권한을 얻어옴( 만약 다른 프로세스/스레드가 임계 구역 수행 중이면 종료할 때까지 대기) • Release lock : 현재 임계 구역에 들어갈 권한을 반환( 대기 중인 다른 프로세스/스레드가 임계 구역에 진입할 수 있음) 뮤텍스는 상태가0, 1로 이진 세마포어로 부르기도 함

뮤텍스 알고리즘 ( 아마 명선이 누나 자료랑 겹칠 듯, 참고용)

  1. 데커(Dekker) 알고리즘 flag와turn 변수를 통해 임계 구역에 들어갈 프로세스/스레드를 결정하는 방식 o flag : 프로세스 중 누가 임계영역에 진입할 것인지 나타내는 변수 o turn : 누가 임계구역에 들어갈 차례인지 나타내는 변수 while(true) { flag[i] = true; // 프로세스i가 임계 구역 진입 시도 while(flag[j]) { // 프로세스j가 현재 임계 구역에 있는지 확인 if(turn ==j) { // j가 임계 구역 사용 중이면 flag[i] = false; // 프로세스i 진입 취소 while(turn ==j); // turn이j에서 변경될 때까지 대기 flag[i] = true; // j turn이 끝나면 다시 진입 시도 } } }

// ——- 임계 구역———

turn =j; // 임계 구역 사용 끝나면turn을 넘김 flag[i] = false; // flag 값을false로 바꿔 임계 구역 사용 완료를 알림 2. 피터슨(Peterson) 알고리즘 데커와 유사하지만, 상대방 프로세스/스레드에게 진입 기회를 양보하는 것에 차이가 있음 while(true) { flag[i] = true; // 프로세스i가 임계 구역 진입 시도 turn =j; // 다른 프로세스에게 진입 기회 양보 while(flag[j] &&turn ==j) { // 다른 프로세스가 진입 시도하면 대기 } }

// ——- 임계 구역———

flag[i] = false; // flag 값을false로 바꿔 임계 구역 사용 완료를 알림 3. 제과점(Bakery) 알고리즘 여러 프로세스/스레드에 대한 처리가 가능한 알고리즘. 가장 작은 수의 번호표를 가지고 있는 프로세스가 임계 구역에 진입한다. while(true) {

isReady[i] = true; // 번호표 받을 준비
number[i] = max(number[0~n-1]) + 1; // 현재 실행 중인 프로세스 중에 가장 큰 번호 배정
isReady[i] = false; // 번호표 수령 완료

for(j = 0;j <n;j++) { // 모든 프로세스 번호표 비교
    while(isReady[j]); // 비교 프로세스가 번호표 받을 때까지 대기
    while(number[j] &&number[j] <number[i] &&j <i);

    // 프로세스j가 번호표 가지고 있어야 함
    // 프로세스j의 번호표< 프로세스i의 번호표
}

}

// ——- 임계 구역———

number[i] = 0; // 임계 구역 사용 종료

뮤텍스와 세마포어의 차이 (중요) ( 면접에 자주 나오는 질문이라고 해요 )

★★★ 가장 큰 차이점은 관리하는 동기화 대상의 개수. Mutex는 동기화 대상이 오직 하나뿐일 때, Semaphore는 동기화 대상이 하나 이상일 때 사용 1) Semaphore는 Mutex가 될 수 있지만 Mutex는 Semaphore가 될 수 없습니다. (Mutex 는 상태가 0, 1 두 개 뿐인 binary Semaphore) 2) Semaphore는 소유할 수 없는 반면, Mutex는 소유가 가능하며 소유주가 이에 대한 책임을 집니다. (Mutex 의 경우 상태가 두개 뿐인 lock 이므로 lock 을 ‘가질’ 수 있습니다.) 3) Mutex의 경우 Mutex를 소유하고 있는 쓰레드가 이 Mutex를 해제할 수 있습니다. 하지만 Semaphore의 경우 이러한 Semaphore를 소유하지 않는 쓰레드가 Semaphore를 해제할 수 있습니다. 모니터 • 세마포어 이후 프로세스 동기화 도구 • 세마포어보다 고수준의 개념 구조 • 공유자원 + 공유자원 접근함수 • 2개의 큐를 가지고 있다. (배타동기 + 조건동기) • 공유자원 접근함수에는 최대 1개의 스레드만 진입할 수 있다. 모니터에는 common variable(공통변수 = 공유자원)이 있고, 그 곳에는 공통변수에 접근할 수 있는 함수들이 있다. 큐는 2개가 양쪽에 존재하는데, 앞쪽의 큐는 상호배제 역할을 하는 큐인데, 예를 들어 공통변수 공간에 스레드가 돌고 있으면, (공유자원을 사용하는 프로세스가 있으면) 앞쪽에 있는 큐가 다른 스레드가 접근할 수 없도록 막고, 그 큐 안에서 스레드가 대기하고 있어야하는 것이다. 공유자원 부분에서는 최대 1개의 함수만(스레드) 들어갈 수 있다. 진입 스레드가 조건동기 큐로 인해서 wait()이 실행된다면, (block)들어왔던 스레드는 조건동기 큐에 블록이된다. 그러면 새 스레드가 진입이 가능하다. 반대로 notify()를 호출하면 조건동기 큐에서 블록되어있던 스레드는 현재 들어가있는 스레드가 나가게되면 다시 들어가게된다. 세마포어에 비해 어려운 것 같아보이지만, 세마포어보다 더 사용하기 수월하다. 자바 모니터 자바의 모든 객체는 모니터가 될 수 있다. 배타동기는 공통변수 공간에 접근할 수 있는 스레드는 오직 하나만 가능해서, 그 다음 스레드가 접근할 수 없도록 하는 것이 배타동기이다. • 배타동기 : synchronized 키워드 사용하여 지정할 수 있다. 공통변수를 업데이트하는 함수가 여러 개 있어서, 한 공통변수가 업데이트되는 함수가 실행되면, 다른 함수는 해당 공통변수를 업데이트하지 못하는 것이다. • 조건동기 : wait(), notify(), notifyAll() 메소드를 사용한다. 스레드가 해당 공통변수 공간에 들어오고 난 후에도 중간에 wait()을 실행시켜 잠시 블록 시켜놓는 상태를 말한다.(스레드는 프로세스이다!!! 해당 돌아가는 함수를 실행시키는 아이) 1. Mutual Exclusion 상호배타 2. Ordering 순서 모니터를 사용하면,(synchronized) 입금이 먼저 일어나고, 출금이 나중에 일어나면, 디파짓의 끝에는 notify()를 넣어주고, 위드로에는 wait()을 넣어준다. 그렇게되면, 입금이 일어난 후에 출금하는 함수를 깨워주고, 출금하는 함수가 실행된 후에는 wait()을 통해 다시 조건동기 큐에 들어가서 블록이 된다. 그러면 입금 함수가 다시 실행되는 식이다. 3. Producer and Consumer Problem 버퍼가 꽉 찼을 때, Producer는 wait()하고, 버퍼가 비어있으면 Consumer가 wait()한다. 그러다가 Consumer가 버퍼를 사용해서 버퍼가 비어지기 시작하면 Consumer가 Producer를 notify()한다. 반대도 마찬가지이다. 4. Readers Writers Problem 5. Dining Philosopher Problem Semaphore와 Monitor의 차이점 세마포어와 모니터 모두 병렬 프로그래밍 환경에서 상호 배제를 달성하는 데 사용되지만이 작업을 수행하는 데 사용되는 기술이 다릅니다. 모니터에서 상호 배제를 달성하는 데 사용되는 코드는 단일 위치에 더 구조화되어있는 반면 세마포어 용 코드는 대기 및 신호 함수 호출로 배포됩니다. 또한 세마포어를 구현할 때 실수하기가 매우 쉽고 모니터를 구현할 때 실수 할 가능성이 거의 없습니다. 또한 모니터는 조건 변수를 사용하지만 세마포어는 사용하지 않습니다.