공유 데이터의 동시 접근은 데이터의 불일치 문제를 발생
일관성 유지를 위해서는 협력 프로세스 간의 실행 순서를 정해야함
Race condition
- 여러 프로세스들이 동시에 공유 데이터를 접근하는 상황
Mutual Exclusion
- 프로세스 Pi가 critical section 부분을 수행 중이면 다른 모든 프로세스들을 그들의 critical section에 들어가면 안된다.
Progress
- 아무도 critical section에 있지 않은 상태에서 critical section에 들어가고자 하는 프로세스가 있으면 critical section에 들어가게 해주어야 한다.
Bounded Waiting
- 프로세스가 critical section에 들어가려고 요청한 후부터 그 요청이 허용될 때까지 다른 프로세스들이 critical section에 들어가는 횟수에 한계가 있어야 한다.
가정
- 모든 프로세스의 수행 속도는 0보다 크다
do {
entry section
critical section
exit section
remainder section
} while (1);
do {
flag[i] = true;
turn = j;
while (flag[i] && turn == j);
critical section
flag[i] = False
remainder section
} while (1);
Busy waiting (spin lock, 계속 CPU와 memory를 쓰면서 wait)
하드웨어적으로 Test & modify를 atomic하게 수행할 수 있도록 지원하는 경우 간단히 해결
Synchronization variable:
boolean lock = False;
Process P
do {
while (Test_and_Set(lock));
critical section
lock = false;
remainder section
} while (1);
두 가지 atomic 연산에 의해서만 접근 가능
P(S): while (S <= 0) do no-op;
S--;
V(S): S++;
Synchronization variable:
semaphore mutext;
Process P:
do {
P(mutex);
critical section
V(mutex);
remainder section
} while (1);
Shared data: buffer 자체 및 buffer 조작 변수 (empty/full buffer의 시작 위치)
Synchronization variables
예시)
semaphore full = 0, empty = n, mutex = 1;
Producer (Consumer는 반대로, P(full), V(empty))
do { ...
produce an item in x
...
P(empty);
P(mutex);
...
add x to buffer
...
V(mutex)
V(full);
} while (1);
한 process가 DB에 write 중일 때 다른 process가 접근하면 안됨
read는 동시에 여럿이 해도 됨
solution
- Writer가 DB에 접근 허가를 아직 못한 상태에서는 모든 대기중인 Reader들을 다 DB에 접근하게 해준다
- Reader들은 다 DB에 접근하게 해준다
- Writer는 대기 중인 Reader가 하나도 없을 때 DB 접근이 허용된다
- 일단 Writer가 DB에 접근 중이면 Reader들은 접근이 금지된다
- Writer가 DB에서 빠져나가야만 Reader의 접근이 허용된다
Shared data: DB 자체, readcount(현재 DB에 접근 중인 Reader의 수)
Synchronization variables
예시)
semaphore mutext = 1, db = 1;
Writer (starvation 발생 가능)
P(db);
...
writing DB is performed
...
V(db);
Reader
P(mutext);
readcount++;
if (readcount == 1)
V(mutex);
...
reading DB is performed
...
P(mutex);
readcount--;
if (readcount == 0)
V(db);
V(mutex);
Synchronization variables
semaphore chopstick[5];
Philosopher i
do {
P(chopstick[i];
P(chopstick[(i+1)%5]);
...
eat();
V(chopstick[i]);
V(chopstick[(i+1)%5]);
...
think();
...
} while (1);
모든 철학자가 동시에 배가 고파져 왼쪽 젓가락을 집어버린 경우, Deadlock 가능성이 있다.
solution
- 4명의 철학자만이 테이블에 동시에 앉을 수 있도록 한다
- 젓가락을 두 개 모두 집을 수 있을 때에만 젓가락을 집을 수 있게 한다
- 짝수(홀수) 철학자는 왼쪽(오른쪽) 젓가락부터 집도록 하게 한다
semaphore self[5] = 0; mutex = 1;
Philosopher i
do {
pickup(i);
eat();
putdown(i);
think();
} while(1);
void putdown(int i) {
P(mutex);
state[i] = thinking;
test((i+4) % 5);
test((i+1) % 5);
V(mutex);
}
void pickup(int i) {
P(mutex);
state[i] = hungry;
test(i);
V(mutex);
P(self[i]);
}
void test(int i) {
if (state[(i+4) % 5] != eating && state[i] == hungry && state[(i+1) % 5 != eating) {
V(self[i]);
}
}
Semaphore의 문제점
- 코딩하기 힘들다
- 정확성의 입증이 어렵다
- 자발적 협력이 필요하다
- 한 번의 실수가 모든 시스템에 치명적 영향
Mutual exclusion 깨짐
V(mutex)
Critical Section
P(mutex)
Deadlock
P(mutex)
Critical Section
P(mutex)
동시 수행중인 프로세스 사이에서 abstract data type의 안전한 공유를 보장하기 위한 high-level synchronization construct
모니터 내에서는 한 번에 하나의 프로세스 만이 활동 가능
프로그래머가 동기화 제약 조건을 명시적으로 코딩할 필요 없음
프로세스가 모니터 안에서 기다릴 수 있도록 하기 위해 condition variable 사용
condition variable은 wait와 signal 연산에 의해서만 접근 가능
monitor bounded_buffer
{ int buffer[N];
condition full, empty;
void produce (int x)
{ if there is no empty buffer
empty.wait();
add x to an empty buffer
full.signal();
}
void consume (int *x)
{ if there is no full buffer
full.wait()
remove an item from buffer and store it to *x
empty.signal();
}
}
monitor dining_philospher
{
enum {thinking, hungry, eating} state[5];
codition self[5];
void pickup(int i) {
state[i] = hungry;
test(i);
if (state[i] != eating)
self[i].wait();
}
void putdown(int i) {
state[i] = thinking;
test((i+4) % 5);
test((i+1) % 5);
}
void test(int i) {
if ((state[(i+4) % 5] != eating) && (state[(i] == hungry) && (state[(i+1) % 5] != eating)) {
state[i] = eating;
self[i].signal();
}
void init() {
for (int i=0; i<5; i++)
state[i] = thinking;
}
}
Each Philosopher:
{
pickup(i);
eate();
putdown(i);
think;
} while(1)