produce과정과 consume과정은 모두 Buffer에 쓰는 과정이기에 (Write) 동시에 한 Process만이 Buffer에 접근해야 함.
Empty: Buffer 내에 저장할 공간이 있음을 표시
생산자의 진입을 관리
Full: Buffer 내에 소비할 아이템이 있음을 표시
소비자의 진입을 관리
Mutex: Buffer에 대한 접근을 관리
생산자, 소비자가 empty, full 세마포어를 진입한 경우, buffer의 상태 값을 변경하기 위한 세마포어
(버퍼에 쓸 공간이 있더라도 누가 이미 쓰고 있을 때를 위해서...)
Full = 0
Empty = n //buffer에 empty인 entry가 n개 (Counting Sem)
Mutex = 1
do {
...
produce an item in nextp
...
P(empty); // 버퍼에 적어도 하나의 공간이 생기기를 기다림
P(mutex); // Critical Section에 진입하기 위해 기다림
...
add nextp to buffer
...
V(mutex); // Critical Section에서 빠져 나왔음을 알림
V(full); // 버퍼에 아이템이 있음을 알림
} while(True);

empty는 n으로 init... => 버퍼의 n칸이 모두 비어있다.
do {
P(full); // 버퍼에 적어도 하나의 아이템이 들어가기를 기다림
P(mutex);
remove an item from buffer to nextc
...
V(mutex);
V(empty); // 버퍼에 하나의 빈 공간이 생겼음을 알림
...
consume the item in nextc
...
} while(True);

full은 0으로 init...

Mutex = 1
Wrt = 1
readcount = 0
P(wrt); // entry section
...
writing is performed
...
V(wrt); // exit section
P(mutex);
readcount++;
if(readcount == 1)
P(wrt); // 어떤 writer도 수행되고 있지 않음을 판별
V(mutex);
...
reading is performed
...
P(mutex);
readcount--;
if(readcount == 0)
V(wrt);
V(mutex);

Readcount == 0 일 때만 V(wrt)가 수행되어 P(wrt)로 대기하고 있던 Writer가 수행할 수 있음
첫 번째 Reader(Readcount == 1)가 P(wrt)만 통과하면, 다른 Reader들은 P(mutex)에 대한 P(mutex)만 기다리면 언제든지 수행할 수 있기 때문에 Writer와 상관없이 진입할 수 있음
여러 Reader들이 계속해서 진입할 경우, Readcount는 0까지 떨어지지 않을 수 있음


do {
...
think
...
P(chopstick[i]); // 왼쪽을 잡을 수 있는가
P(chopstick[(i + 1) % 5]) // 오른쪽을 잡을 수 있는가
...
eat
...
V(chopstick[i]);
V(chopstick[(i + 1) % 5]);
...
} while(True);
동시에 chopstick을 잡으면 deadlock 발생
-> 모두가 왼쪽을 잡으면... (= P(chopstick[i]); 이후에...)

0번이 자신의 왼쪽 젓가락을 든 이후에 Deadlock에 빠졌다
(= 모든 철학자들(프로세스들)이 자신의 왼쪽 젓가락을 들었다)
mutex : 젓가락을 집거나 놓는 수행을 Critical Section으로 관리하기 위한 세마포어
초기값 = 1
self[5] : 철학자 각각이 젓가락 두 개를 잡기를 기다리는 세마포어
초기값 = 모든 원소가 0
self[i] 의미는 철학자i가 HUNGRY 상태이더라도, 다른 젓가락 하나를 사용할 수 없을 경우 Waiting을 하기 위한 세마포어
do {
...
think
...
take_chopsticks(i);
...
eat
...
put_chopsticks(i);
...
} while(True);
take_chopstick(int i){
P(mutex);
state[i] = HUNGRY;
test(i);
V(mutex);
P(self[i]);
}
put_chopstick(int i){
P(mutex);
state[i] = THINKING;
test(LEFT);
test(RIGHT);
V(mutex);
}
test(int i) {
if(state[i] == HUNGRY && // 내가 배고프고 양쪽이 먹고 있지 않은(NOT EATING) 상태일 때
state[LEFT] != EATING &&
state[RIGHT] != EATING){
state[i] = EATING;
V(self[i]);
}
}
take_chopstick() : Mutex를 통해 진입하여, test(i)를 통해 양쪽의 철학자 상태를 검사한 후, 자신이 먹을 차례를 기다린다.
put_chopstick() : Mutex를 통해 진입하여, test(LEFT), test(RIGHT)를 통해 양쪽의 철학자 상태를 검사한 후, 먹을 차례를 기다리는 철학자에게 signal을 보내준다.
test() : Test를 수행한 철학자(i)가 HUNGRY 상태이고, 양쪽의 철학자가 모두 젓가락을 집지 않은 상태 (NOT EATING)이면 take_chopsticks()에서 wait했던 자신의 세마포어 self[i]에 signal을 보내어 EAT으로 진행하도록 함
test() 함수 안에서 검사하는 LEFT와 RIGHT의 상태가 EATING이 아니어야 함
test()를 만족하면, signal(self[i])에 의해 self[i]의 값은 1이 되므로, wait(self[i])에서 block되지 않고 식사를 진행한다.
self[i]의 초기 값은 0임

이 때, 철학자 L과 R은 i에 의해 take_chopstick()에서 wait()함수에 의해 대기 중
철학자 i에 의해 실행한 test(LEFT)
i와 LL의 상태를 확인
철학자 i에 의해 실행한 test(RIGHT)
i와 RR의 상태를 확인
철학자 i가 식사중인 동안 LL 혹은 RR 철학자의 상태가 EATING으로 바뀐다 하더라도, test(LEFT)와 test(RIGHT)를 통해 signal을 수행하므로 동기화에 문제가 없다.