본 게시글은 하단 책을 읽고 학습한 내용을 제 생각으로 요약, 정리한 글입니다.
목차
1. 프로세스 간 통신(InterProcessCoummunication)이란?1) 프로세스 간 통신의 세 가지 이슈2. 경쟁조건(Race Conditions)1) 경쟁조건(Race Conditions)3. 임계구역(Critical Regions)1) 상호배제(Mutual Exclusion)2) 임계구역(Critical Region)3) 경쟁조건(Race Conditions) 방지하는 조건4. 바쁜 대기를 이용한 상호배제(Mutual Exclusion with Busy Waiting)1) 인터럽트 끄기(Disabling Interrupts) → 비추(권한 남용)2) 락 변수 사용(Lock Variables) → 실패(상호배제 x)3) 엄격한 교대(Turn) → 비추(조건3 x)4) Peterson의 해법 → 성공(Turn 변형)5) TSL 명령 → 성공(Lock 변형)5. Sleep and Wakeup1) 바쁜 대기의 단점2) Sleep과 Wakeup3) Sleep과 Wakeup 사용 예시: 생산자-소비자 문제(Producer-consumer problem) 해결 → 실패 (경쟁조건 발생)6. 세마포어(Semaphores)1) 세마포어2) 세마포어를 이용한 생산자-소비자 문제 해결 → 성공7. 뮤텍스(Mutexes)1) 뮤텍스 [개념적인 것만 알기]2) TSL로 mutex 구현한 코드3) mutex_lock vs. enter_region8. 모니터(Monitors)1) 세마포어의 문제점2) 모니터3) 조건 변수(Condition Variables)와 관련 연산 wait, signal4) 모니터를 사용한 생산자-소비자 문제 해결9. 메시지 패싱(Message Passing)1) 메시지 패싱2) N개 메시지에 대한 생산자-소비자 문제10. 장벽(Barriers)1) 장벽
1. 프로세스 간 통신(InterProcessCoummunication)이란?
1) 프로세스 간 통신의 세 가지 이슈
- 한 프로세스가 다른 프로세스에게 정보 어떻게 넘겨줄래
- 프로세스들이 완전히 다른 주소공간에서 동작한다면 공유메모리를 어떻게 공유할것인가
1) 세마포어 같은 공유자료구조를 커널에 저장하고 시스템호출로만 접근
2) 프로세스의 주소 공간 일부분을 다른 프로세스와 공유
3) 위 두 가지 다 안되는 경우 공유 파일을 사용
- 두 개 이상의 프로세스가 임계구역에 참여하고 있을 때, 상대방 방해하지 않도록 어떻게 할래
- 상호배제 적용
- 프로세스 간에 종속성 존재할 때 순서 어떻게 매길래
ex) 서연이가 데이터 생성하고 기우는 생성된 데이터 출력한다면 기우는 서연이 기다려야함
2. 경쟁조건(Race Conditions)
1) 경쟁조건(Race Conditions)
- 정의) 둘 이상의 프로세스가 동시에 공유데이터를 읽거나 기록할 때 최종 결과가 누가 언제 수행되느냐에 따라 달라지는 상황
- 예시) 프린트 스풀러
- 스풀러 디렉터리: 프로세스가 프린트하고 싶은 파일 이름 기입한 곳
- out: 프린트할 다음 파일 가리키는 공유 변수
- in: 다음 빈 슬롯 가리키는 공유 변수. in, out은 보통 한 파일에 존재
- 프린터 데몬 프로세스: 주기적으로 스풀러 디렉터리 살펴서 프린트할 파일 있나 검사하고, 있으면 파일 프린트하고 이름을 디렉터리에서 지우는 프로세스. out을 하나 증가시킴.
- 서연이가 파일 출력하고 싶어서 print 루틴 콜함.
- 서연이가 in 값 7을 읽어서 서연이의 지역변수에 저장해둠.
- 서연이가 다음 단계(파일이름쓰기) 가려는데 CPU가 할당된 시간 다됐다고 ready로 보내버림. 그리곤 기우를 running으로 올림.
- context switch 발생
- 기우도 파일 출력하고 싶어서 print 루틴 콜함.
- 기우가 in 값 7을 읽어서 본인 로컬변수에 저장함.
- 기우가 7 자리에 기우가 출력하고 싶은 파일 이름 씀
- [7]=기우짱.c
- 기우가 8로 증가시킨 로컬변수 값으로 in을 덮어쓰기함
- in = 8
- CPU가 시간 다 됐다고 기우를 끌어내리고 언젠가 다시 서연이 차례가 됨
- context switch 발생
- 서연이는 전에 읽어둔 in 값이 7이라서 7자리에 파일 이름 씀
- [7]=서연최고.c → 기우짱.c 덮어씀
- 서연이는 8로 증가시킨 로컬변수 값으로 in을 덮어쓰기함
- in = 8 → 8을 덮어씀
- 서연최고.c만 출력됨
- 프린터 데몬 프로세스는 스풀러 디렉터리의 일관성 홰손 안돼서 잘못된 사실 인지 못함
- 만일 서연이가 in 증가까지 다 끝낸다음 기우가 수행됐으면 둘다 잘 출력됐겠지 → 경쟁조건

경쟁조건 발생 과정)
3. 임계구역(Critical Regions)
1) 상호배제(Mutual Exclusion)
- 정의) 한 프로세스가 공유데이터를 읽거나 쓰고 있으면 다른 프로세스들은 똑같은 일을 수행하지 못하도록 하는 것(배제)
- 공유데이터: 공유 변수나 파일
- 둘 이상의 프로세스가 동시에 공유 데이터에 읽기나 쓰기 수행 못하도록 금지하는 것
2) 임계구역(Critical Region)
- 정의) 공유메모리에 접근하는 프로그램의 코드 부분
- 공유메모리 그 자체가 아님.
3) 경쟁조건(Race Conditions) 방지하는 조건
- 상호배제 제공 → 어느 두 개의 프로세스도 동시에 임계구역에 있지 못하게 함
- 서연이가 임계구역에 있는 동안 기우가 임계구역 들어가려 시도하는 상황
- 상호배제를 제공하면 기우가 차단됨.
- 서연이가 임계구역 떠나야(공유 데이터 사용하는 코드 수행 완료해야) 들어갈 수 있음.
임계구역 사용한 상호배제 그림

- CPU의 개수나 속도에 대한 가정 x
- 임계구역 밖에서 수행 중인 프로세스는 다른 프로세스를 block 시키면 안됨
- 임계구역에 들어가려는 다른 프로세스를 막으면 안됨
- 임계구역 들어가려고 무한히 기다리는 프로세스 없어야 함
4. 바쁜 대기를 이용한 상호배제(Mutual Exclusion with Busy Waiting)
- 바쁜 대기 이용해 상호배제 제공(구현)하는 방법들 4가지
1) 인터럽트 끄기(Disabling Interrupts) → 비추(권한 남용)
- 정의) 임계구역에 진입한 직후 모든 인터럽트를 비활성화하고, 떠나기 직전 다시 활성화함
- 장점) 한 프로세스가 임계구역에 있는 동안 CPU가 clock interrupt에 반응하지 않아 process switch가 일어나지 않게 함으로써 상호배제를 제공함
- 단점) 사용자 프로세스에게 인터럽트 껐다 켤 수 있는 권한 주는 거라 현명 x
- 프로그래머가 인터럽트 활성화 명령 까먹으면 해당 시스템은 인터럽트에 영원히 반응하지 못해 process switch가 안 일어나서 더 이상 동작하지 않음.
- process switch(=context switch):한 프로세스 수행하다 다른 프로세스 수행하는 것
- 프로세스에 할당된 시간 끝나서 clock interrupt 걸리면 running 상태 프로세스를 ready로 보내고 다른 프로세스를 running하는 process switch일어남
- interrupt disable 명령어
- interrupt CPU가 interrupt pin으로 받은 interrupt signal에 대해 반응하는 것인데,
- CPU가 interrupt disable 명령어 수행하면 해당 CPU는 인터럽트에 반응하지 않게 됨.
- 인터럽트 비활성화 사용하는 다른 예
- 커널이 변수나 리스트 변경하는 단 몇 개의 명령만을 수행하는 동안 인터럽트 비활성화시킴
2) 락 변수 사용(Lock Variables) → 실패(상호배제 x)
- Lock 변수: 임계구역에 프로세스가 있고 없고를 나타내는 공유변수. 초기값은 0.
- 0 → 임계구역에 어떤 프로세스도 없음
- 1 → 임계구역에 어떤 프로세스가 있음
- 정의) 임계구역 들어가기 전에 락 변수를 살펴봄.
- 0 → 1로 변경하고 임계 영역으로 들어감
- 1 → 0이 될 때까지 대기함
- 단점) 스풀러 디렉터리와 동일한 문제점 가짐: 상호배제 제공 못해 경젱조건 못피함.
- 서연이가 락 검사 끝내고 락을 1로 변경하는 사이에 기우가 락을 1로 변경하면 기우랑 서연이랑 동시에 임계구역에 들어가면서(상호배제 깨짐) 경쟁조건 발생함.
- 특징) 소프트웨어 솔루션임
3) 엄격한 교대(Turn) → 비추(조건3 x)
- 정의) 두 프로세스가 엄격하게 교대로 임계구역에 진입하게 함
- turn: 임계구역에 진입할 순번 나타내는 공유변수. 초기값은 0
- 0 → 서연 차례
- 1 → 기우 차례
- 임계영역 들어가기 전에 turn 변수를 살펴봄
- 서연
- 0 → 1로 변경하고 임계 영역에 들어감.
- 1 → 0이 될 때까지 기다림
- 기우
- 1 → 0으로 변경하고 임계 영역에 들어감.
- 0 → 1이 될 때까지 기다림
서연 코드 → turn이 0이면 임계구역에 들어감.
기우 코드 → turn이 1이면 임계구역에 들어감.
- 장점) 상호배제 제공해(조건1) 경쟁조건 피할 순 있음
- 서연이가 임계구역에 들어가있는동안 기우는 turn이 0이라서 임계구역에 들어갈 수 없음. → 상호배제 제공
- 서연이가 임계구역에서 나오고 turn을 1로 설정하는 순간 기우는 while문 빠져나오면서 임계구역에 들어감
- 단점)
- 상호배제 제공(조건1)해도 조건3을 위반해서 완벽한 알고리즘 아님.
- 임계영역에 있지 않은 프로세스가 다른 프로세스를 차단함
- 기우 임계구역 실행 후 turn=0으로 변경 → 서연 임계구역 실행 후 turn=1로 변경, 기우는 비임계구역 실행 중 → 기우가 임계구역 실행할 차례인데 기우는 아직 비임계구역 실행 중이고 서연이가 임계구역 실행 원함. 허나 turn=1이라서 기우가 임계구역 실행하고 turn=0으로 바꿔줄 때까지 서연이는 블락됨.
- 비임계구역의 기우가 임계구역 들어가고 싶은 서연이를 막는 상황.
- ex) 스풀러 디렉터리
- 서연이가 파일 프린트하고, 기우가 파일 프린트해야 서연이는 다음 자기 파일을 프린트 가능한 답답한 상황 발생. 번갈아가면서 할 때만 제대로 작동함.
- 기우가 서연이보다 훨씬 느릴 때 교대로 진행하는 것은 좋지 않음
- 바쁜 대기(Busy Waiting)
- 정의) 변수가 특정값이 될 때까지 계속해서 검사하는 것
- 단점) CPU 시간을 단순한 루프 도는데에 낭비해서 피하는 게 좋음
- 루프 도는 대기 시간 짧을 게 예상되는 경우에만 사용
- 스핀 락(Spin Lock) : 바쁜 대기를 사용하는 락 → turn
4) Peterson의 해법 → 성공(Turn 변형)
- 코드
- 임계구역 들어가기 전에 서연이랑 기우는 자기번호를 인자로 해서 enter_region을 호출함
- 임계구역에 들어가서 공유변수 사용을 마친 서연이는 leave_region을 호출해서 서연이가 임계구역 수행 종료하고 관심 없다고 밝혀서 임계구역 진입 원하는 기우가 진입할 수 있음을 알려줌 (상호배제 제공)
ex) 서연, 기우가 동시에 call
- 서연 : interested[서연]=true, turn=서연
- 기우 : interested[기우]=true, turn=기우
- 서연 : while (자기차례아님, 상대는 관심있음) -> 임계구역 들어감
- 기우 : while (자기차례임, 상대는 관심있음) -> 임계구역 못들어감(기우가 서연이 turn 덮어써서 차례가 기우인것뿐, 서연이가 관심없어질때까지 못들어감)
- 현재 자기차례고 상대가 관심있단건 내가 나쁜놈인거임. 기다려.
- 자기차례인데 상대관심없어지거나
- 자기차례아닐때까지 기다려야함. (상대가 다 쓰고서 한번 더 쓸려 하는 거임. 나쁜 놈
- 서연 : interested[서연]=false -> 임계구역 나감
- case 1)
- 서연: interested[서연]=true, turn=서연
- 기우 : while (자기차례아님, 상대는 관심있음) -> 임계구역 들어감
- case 2)
- 기우: 드디어 while (자기차례임, 상대는 관심없음) -> 임계구역 들어감
- 기우 : interested[기우]=false -> 임계구역 나감
- 기우 : interested[기우]=true, turn=기우
- 기우 : while (자기차례임, 상대는 관심없음) -> 임계구역 들어감
- 장점) 엄격한 교대 요구하지 않으면서 상호 배제 제공함
5) TSL 명령 → 성공(Lock 변형)
- 정의) Lock 변수 값을 register에 복사해두고 lock 변수값을 무조건 1로 세팅한 후, register에 복사해둔 이전 Lock값을 살펴봄
- 0 → 1로 변경하고 임계 영역으로 들어감
- 1 → 0이 될 때까지 대기함
- Lock: 임계구역에 프로세스가 있고 없고를 나타냄. 초기값 0(프로세스 없음)
- 어셈블리 코드
- 서연이가 임계구역 들어가고 싶어서 lock을 1로 설정함
- 서연이가 봤을 때 설정 전 락은 0이었기에 서연이는 임계구역에 들어감
- 기우가 임계구역 들어가고 싶어서 락을 1로 설정함
- 기우가 봤을 때 설정 전 락은 1이었기에 기우는 임계구역에 못들어가고 락이 0이 될 때까지 락을 1로 계속해서 설정하며 루프 돔.
- 서연이가 임계구역 나와서 락을 0으로 바꿈
- 기우가 락을 1로 설정하지만 이번엔 설정 전 락이 0이었기에 임계구역 들어감
- TSL 명령
- test and set lock
- lock 값 읽어서 레지스터에 저장하고 lock에 0이 아닌 값을 저장함
- TSL 명령 수행 끝날 때까지 메모리 버스 잠겨서 다른 어떤 CPU도 메모리 접근 불가함
- vs. 인터럽트 비활성화 → 인터럽트 끄는 것은 다른 CPU 못막음
→ 하나의 연산. 분할 불가능. 연산 중간에 process switch 일어날 수없음
- 특징)
- 하드웨어 도움 받음
- 분할 불가능함(indivisible)
- 단점)
- 프로세스가 enter_region, leave_region을 제때 호출안하면 상호배제 실패함
5. Sleep and Wakeup
1) 바쁜 대기의 단점
- 임계구역 진입이 허용되지 않을 때 루프를 돌며 CPU 시간 낭비
- 우선 순위 역전 문제 [참고로만 알기]
2) Sleep과 Wakeup
- 임계구역 진입이 허용되지 않을 때 바쁜 대기 안하고, block함
- Sleep
- 호출자를 block 상태로 만드는 시스템 호출
- 다른 프로세스가 Wakeup 시스템 호출로 깨워줄 때까지 block 상태에 머물게 됨
- Wakeup
- 깨울 프로세스를 인자로 가져 깨워서 ready 상태로 보내주는 시스템 호출
3) Sleep과 Wakeup 사용 예시: 생산자-소비자 문제(Producer-consumer problem) 해결 → 실패 (경쟁조건 발생)
- 생산자-소비자 문제
- 정의) 생산자는 공유버퍼에 아이템 계속 생산하고, 소비자는 아이템 계속 소비하는 개념
- 두 프로세스가 고정된 크기의 버퍼를 공유함
- 생산자(서연이)가 정보를 버퍼에 넣고, 소비자(기우)는 정보를 버퍼에서 꺼내옴
- Sleep, Wakeup 사용한 생산자-소비자 문제 해결
- 서연이가 새로운 아이템을 버퍼에 넣고 싶은데 버퍼가 이미 꽉 찬 경우 기우가 버퍼에서 아이템 꺼내갈 때까지 sleep 상태가 됨
- 기우가 아이템 버퍼에서 꺼내오고 싶은데 버퍼에 아무것도 없는 경우 서연이가 버퍼에 아이템 넣어줄 때까지 sleep 상태가 됨
- 따라서, 서연이는 아이템 넣었을 때 기우를 wakeup 해줘야하고, 기우는 아이템 꺼내 제거했을 때 서연이를 wakeup 해줘야함.
- 코드
- 단점) 스풀러 디렉터리에서 봤던 경쟁조건 일어남
- 정의) 아직 sleep 상태가 아닌 프로세스에게 wakeup 전송하는 경우 wakeup이 소실되어 둘다 영원히 잠들게 되는 결과 초래됨
- 원인) sleep() 콜하기 직전에 process switch 일어나면(교묘하게 스케줄링 되면) sleep() 안된 상태로 wakeup() 받는 상황 발생함
- 기우가 count 값 읽어서 0인걸 알게 됨
- 기우가 다음 동작 수행 하려는데, 스케줄러가 기우 수행 중지시키고 서연이를 수행하기 시작함
- 기우가 sleep() 콜하기 전에 process switch가 발생함
- 서연이가 아이템을 버퍼에 추가하고 count를 증가시켜 count 값이 이제 1이 됨
- count가 이전에 0이었으므로 기우가 잠들어있을것이라 생각한 서연이는 기우를 깨우기 위해 wakeup을 호출함
- 불행하게도 기우는 아직 잠든 상태가 아니라서 서연이의 wakeup 시그널은 허무하게 사라짐
- 기우가 다시 실행 재개할 때 기우 입장에선 예전에 읽었던 count값이 0이기에 sleep()을 콜함.
- 조만간 서연이는 버퍼를 다 채우고 잠들게 됨
- 기우랑 서연이 둘다 영원히 잠듦
경쟁조건 발생 과정
6. 세마포어(Semaphores)
1) 세마포어
- 정의) 미래를 위해 미리 호출한 wakeup 회수를 저장해주는 변수 타입
- 다익스트라가 제안한 새로운 변수 타입
- 정수 변수
- 0 → wakeup이 저장 안됨
- 양수값 → 하나 이상의 wakeup이 대기 중
- 장점) 경쟁조건 방지, 동기화 문제 해결
- 세마포어 연산의 원자성이 보장되어 연산 시작하면 연산 완료되거나 프로세스가 잠들 때까지 다른 프로세스가 세마포어에 접근 불가
- 연산
- down(P)
- up(V)
- mutual exclusion 제공하는 법: down 연산 → critical region → up 연산
- up, down연산은 원자성 보장되어 실행 중 중단되지 않음.
- 일반적으로 인터럽트 비활성화하는 시스템호출로 구현됨
- 따라서 down에서 세마포어 값 검사한 후 감소시키는 중간에 process switch가 일어나지 않음.
2) 세마포어를 이용한 생산자-소비자 문제 해결 → 성공
- 세마포어는 wakeup이 소실되는 문제를 해결함
- 상호배제용 세마포어: mutex
- 서연이랑 기우가 동시에 버퍼에 접근하지 못하게 함
- 이진 세마포어임
- 이진 세마포어: 1로 초기화되고 둘 이상의 프로세스에서 사용될 때 오직 하나의 프로세스만 critical region에 들어갈 수 있게 함
- 1이면 임계지역 들어갈 수 있음. 임계지역 아무도 사용 x.
- 0이면 임계지역 못들어감. 임계지역 사용 중.
- 동기화용 세마포어: full, empty
- 버퍼가 가득 차거나 비었을 때 서연이나 기우가 중지되는걸 보장함
- down(&sema)
- 서연이가 down(empty) 호출해서 empty(빈 슬롯 개수, 초기:N)가 0이면(버퍼가 꽉 차있다면) 잠들어. empty가 0보다 크면 empty 1 감소시켜(아이템을 하나 넣을 예정)
- 혹은 기우가 down(full) 호출해서 full(찬 슬롯 개수, 초기:0)이 0이면(버퍼가 텅 비어있다면) 잠들어. full이 0보다 크면 full 1 감소시켜(아이템을 하나 뺄 예정)
- 임계지역 들어가려는 누군가가 down(mutex) 호출해서 mutex가 0이면 잠들어. mutex가 1이면 mutex 1 감소시켜서 0으로 만들어(임계지역 들어가서 버퍼 건들 예정)
- up(&sema)
- 기우가 up(empty) 호출해서 서연이가 잠들어있으면 서연이를 깨워줘. 서연이가 잠들어있지 않다면 empty하나 늘려서 1로 만들어.
- 혹은 서연이가 up(full) 호출해서 기우가 잠들어있으면 기우를 깨워줘. 기우가 잠들어있지 않다면 full 하나 늘려서 1로 만들어.
- 임계지역에서 나오는 누군가가 up(mutex) 호출해서 임계지역 못들어온채 잠들어있는 애 있다면 걜 깨워줘. 잠든 애 없다면 mutex 1 증가시켜서 1로 만듬(사용가능상태로 만듬).
- 코드
7. 뮤텍스(Mutexes)
1) 뮤텍스 [개념적인 것만 알기]
- 정의) 세마포어의 개수 세는 능력이 빠진 단순화된 버전
- 언락: 임게구역 사용 가능 → 0
- 락: 임계구역 사용 안됨 → 1
- 특징)
- 상호배제용으로 씀
- mutex_lock, critical region, mutex_unlock 순으로 사용
- 뮤텍스는 세마포어가 아님
- 스레드 패키지에 유용
- 프로시저 레벨이 아닌 스레드 레벨에서 부르는 코드
2) TSL로 mutex 구현한 코드
- 스레드가 임계구역 접근시 mutex_lock (뮤텍스가 잠겨있닝? 나 걔 써서 잠그고 시퍼) 호출함.
- 안잠겨있어! 너 써! mutex가 언락이면 임계구역을 사용할 수 있단 뜻으로 return되고, 스레드는 임계구역에 진입할 수 있음
- 응~잠겨있어~ mutex가 락이면 스레드는 thread_yield해서 ready로 감. 현재 임계구역에 있는 애가 수행 다 마치고 mutex_unlock (뮤텍스 풀어줘~ 나 다썼어) 호출하고 나서, 언젠가 running으로 다시 올라가면 mutex_lock 다시 수행하고 그땐 mutex 안잠겨있어서 return되고 임계구역 진입할 수 있음
3) mutex_lock vs. enter_region
- enter_region은 임계구역 진입 못하면 락을 반복적으로 검사함.
- 바쁜대기(락 반환될 때까지)
- mutex_lock은 락 획득 못해서 바쁜대기를 수행하는 스레드가 다른 프로세스가 수행될 기회조차 안줘서 영원히 락 획득 못하는 무한루프에 빠지는 걸 막기 위해, 락 획득 못할 시 thread_yield를 호출해 다른 스레드에게 cpu를 양보함
- 바쁜 대기 존재 안함
- 스레드 다시 수행하게 되면 락 다시 검사함
- thread_yield는 사용자 공간의 스레드 스케줄러를 호출해 매우 빠름
- 커널 호출하지 않음. 사용자 레벨 스레드들은 mutex_lock 이용하면 전적으로 사용자공간에서 동기화 수행 가능함.
8. 모니터(Monitors)
1) 세마포어의 문제점
- 사용이 어려움.
- 기우는 down(mutex)해서 mutex값을 1에서 0으로 바꿈.
- 0이면 서연인 임계지역 못들어옴
- 기우가 down(full)했더니 버퍼가 비어있어서 full이 0이라 잠듦
- 서연이가 버퍼 넣어주려고 down(empty) 후에 down(mutex)했더니 mutex가 0이라 잠듦
- 둘다 영원히 잠듦
예시) 프로그래머가 실수로 기우의 down(full)이랑 down(mutex) 순서 바꾼 상황
2) 모니터
- 정의) 모듈 또는 패키지에 모아진 프로시듀어, 변수, 자료구조의 모음
- 특징)
- 높은 수준의 동기화 프리미티브
- 상호배제 제공
- 모니터의 자료구조는 모니터 내부의 프로시듀어만 직접 접근 가능하고,
- 프로세스는 모니터의 프로시듀어를 호출함
- 모니터 프로시듀어 호출 시 다른 프로세스가 모니터에서 활동 중인지 검사함
- 활동 중인 프로세스 O → 다른 프로세스가 모니터에서 나올 때까지 중단됨
- 활동 중인 프로세스 X → 모니터에 진입함
- 상호배제 구현은 이진 세마포어나 뮤텍스 사용해 컴파일러가 함. (잘못될 가능성↓)
단 하나의 프로세스만 한 순간에 모니터에서 활동 가능
- 단점
- 컴파일러에서 지원해야 함
- 분산 환경에서 적용할 수 없음
- 코드
3) 조건 변수(Condition Variables)와 관련 연산 wait, signal
- 프로세스가 진행 불가할 때 대기할 수 있는 방법 (버퍼가 가득 차면 서연이는 어떻게 블록시켜?)
- 조건변수와 조건변수에 대한 연산 wait, signal 도입해서 해결
- wait
- 서연이가 호출한 모니터 procedure가 버퍼가 가득 차 있어서 더 이상 진행할 수 없음을 알게 된 경우,
- 조건 변수(full)에 대해 wait를 수행해 호출한 프로세스 서연이를 대기하게 만듦.(block)
- 다른 프로세스(기우)가 모니터에 들어갈 수 있게 함.
- signal
- 기우가 조건 변수(full)에 대해 signal을 수행해 대기 중인 서연이를 깨움.
- signal 이후 서연이랑 기우가 동시에 모니터에서 활동하는걸 막을 규칙
- signal 수행한 프로세스인 기우가 즉시 모니터에서 나가고
- full에 대해 대기 중인 프로세스 중 스케줄러가 택한 프로세스(ex. 서연이) 하나가 깨어나 수행됨
- 기우가 즉시 나가야하기에 signal은 모니터 procedure의 맨 마지막에서 사용되어야함
- 조건변수
- 세마포어처럼 카운터가 아니라서 signal을 누적시킬 수 없음
- 아무도 대기하고 있지 않은 조건변수에 대해 수행된 signla은 사라짐
- 따라서 signal 전엔 무조건 wait가 수행되었어야 함
4) 모니터를 사용한 생산자-소비자 문제 해결
- 코드
- wait, signal vs. sleep, wakeup
- sleep, wakeup
- 버퍼 찬 거 확인하고, sleep 하려는 사이에 process switch일어나서 다른 프로세스가 이 프로세스를 wakeup 하려하면 wakeup이 소실되고 문제 발생함
- wait, signal
- 모니터 프로시듀어에 대해 자동으로 상호배제 이뤄짐
- 모니터의 생산자 프로시듀어가 버퍼 찬 거 확인하고, wait 하려는 사이에 소비자로 process switch될 일 없이 wait 완료할 수 있음.
- 소비자는 생산자가 wait 완료하고 더 이상 실행 중이지 않다고 표시할 때까지 모니터 진입 불가함.
9. 메시지 패싱(Message Passing)
1) 메시지 패싱
- 정의) 프로세스들이 네트워크로 연결된 각기 다른 컴퓨터에서 수행되어 메모리를 공유하고 있지 않아 공유변수 사용이 불가능한 상황에서 사용하는 ipc(프로세스 간 통신) 방식
- 특징) 시스템 호출 send와 receivce 사용
- send(destination, &message)
- 지정된 목적지(프로세스)로 메시지 보냄
- receive(source, &message)
- 지정된 소스(프로세스)로부터 메시지 받음
- 메시지가 available하지 않으면 receive 시스템콜 호출한 프로세스는 메시지가 도착할 때까지 block되거나(아래 코드가 채택) receive 시스템콜이 오류 코드와 함께 즉시 return됨
2) N개 메시지에 대한 생산자-소비자 문제
- 코드 → 공유버퍼를 구현한 셈
- 서연이가 아직 아이템 넣은 메시지 안보냈다면 기우는 while루프에서 receive system call했을 때 block이 됨
- 동기화를 잘 구현한 것임
- 서연이는 버퍼 꽉 찼으면 더 진행 못하고 기우는 버퍼 텅 비어있으면 더 이상 진행 못한다는 생산자-소비자 문제의 컨셉이 잘 구현됨.
10. 장벽(Barriers)
1) 장벽
- 정의) 다른 모든 프로세스가 장벽에 도착할 때까지 이미 도착한 프로세스들은 대기. 모든 프로세스가 장벽에 도착하면 다같이 장벽을 통과함.
- a,b,d가 barrier primitive를 call함. 아직 c가 call하지 않아서 a,b,d는 block
- c가 barrier primitive를 call하면 a,b,c,d가 barrier primitive로부터 return함

- 특징) 여러 프로세스 동기화할 때 사용
