운영체제 10 -...
Transcript of 운영체제 10 -...
운영체제 10주차부산가톨릭 대학교, 컴퓨터공학과
변상선
Process synchronization
• 여러 프로세스 또는 쓰레드가 동시에 (concurrently) 공유 자원 (공유 변수)에 접근 할 때 단 하나의 프로세스 또는 쓰레드만 접근 할 수 있도록 보장해 주는 기법
• 공유자원 => critical section (임계영역)
• 동시에 수행되는 협조관계에 있는 프로세스/쓰레드들의 연산들이 서로 의존적인 경우 => 반드시, 쓰레드 A의 덧셈 연산이 먼저 수행되고 난 후, 쓰레드 B의 덧셈이 수행되어야 한다
• 이러한 서로 협조관계에 있는 프로세스/쓰레드의 의존적인 연산 순서를 제어해 주는 기법
Race condition• int counter;
Process A { … counter++; … } Process B { … counter—; .. }
• counter++
• register1 = counterregister1 = register1 + 1counter= register1
• counter—
• register2 = counterregister2 = register2 - 1 counter = register2
Race condition
• When initially “count = 5”
• S0: PA register1 = counter (register1 = 5) S1: PA register1 = register1+1 (register1 = 6) S2: PB register2 = counter (register2 = 5) S3: PB register2 = register2-1 (register2 =4) S4: PA counter = register1 (counter = 6) S5: PB counter = register2 (counter = 4)
Critical section problem
• 어느 시점에라도 단 하나의 프로세스만이 임계영역에 있도록 보장
• 하나의 프로세스가 임계영역에 있으면 다른 프로세스는 그 프로세스가 임계영역을 떠날 때까지 기다려야 함 => wait
Critical section
Solution to critical section problem
• Mutual exclusion
• 단 하나의 프로세스 만이 임계영역에 진입할 수 있도록 보장
• Progress
• 하나이상의 프로세스가 임계영역에 진입하려고 한다면 remainder section에 있지 않은 프로세스들만이 누가 CS에 들어갈 지 결정하는데 참여할 수 있고, 이 결정은 무한정 연기될 수 없다
• Bounded waiting
• 하나의 프로세스가 임계영역 진입 요청을 한 시점부터 허가를 받기까지 사이에 다른 프로세스들이 임계영역에 들어가는 횟수에는 제한이 있다
• 프로세스 A가 임계영역 진입 요청을 한 상태이면, 다른 프로세들은 임계영역에 들어가는 횟수에 제한을 두고, 그 제한된 횟수 만큼 임계영역에 진입하였다 나왔다면, 반드시 프로세스 A에게 임계영역 진입을 허가해야 한다 => 임계영역에 들어가기 위해 무한정 기다리게 하지 않는다
Peterson’s solution• For two processes
• 다음의 변수를 공유
• int turn; boolean flag[2];
• turn: 두 프로세스 가운데 누가 CS 로 들어갈 차례인가?
• flag: flag[i] = true 면, 프로세스 i가 CS로 들어갈 준비가 되었음
Algorithm for process Pi• do {
flag[i] = true; turn = j; // process j가 CS로 들어가는 것을 보장 while (flag[j] && turn == j); critical section flag[i] = false; remainder section} while (true);
• 만약, 둘다 turn=i, turn=j를 동시에 쓰려고 해도, 결과적으로는 둘 중 조금이라도 늦게 쓴 값이 turn에 저장 => 즉, 먼저 turn에 값을 쓴 프로세스가 진행=> 결국 하나의 프로세스 만이 CS에 진입 가능 (flag[i], flag[j]가 둘다 true라고 하더라도) => mutual exclusion 보장
• CS를 빠져나가면서 flag[]를 false로 따라서, while()에서 대기중이었던 다른 프로세스가 곧바로 CS로 진입 가능 => progress, bounded-waiting 모두 만족
Peterson’s solution
• Pi do { flag[i] = true; turn = j; while (flag[j] && turn == j); critical section flag[i] = false; remainder section} while (true);
• Pj do { flag[j] = true; turn = i; while (flag[i] && turn == i); critical section flag[j] = false; remainder section} while (true);
Synchronization hardware
• Hardware support for CS code
• Protecting CS via locks
• 인터럽트 불허
• Uniprocessor system
• 공유변수 변경되는 동안 모든 인터럽트 불허
• 비선점형 커널
• Multiprocessor system
• 모든 프로세서에게 인터럽트 불허 메시지 전달 => 비효율적
• 인터럽트에 의해 시스템 클록이 갱신된다면? => 클록 갱신에 지연 발생
• 하드웨어 상에서 atomic operation 지원 => API를 통해 사용 가능
• while (test_and_set(&lock)) ; //do nothing// critical section
• lock을 획득하기 위한 동작 test_and_set을 계속 실행 => atomic
Bounded-waiting mutual exclusion with test_and_set
do { waiting[i] = true; key = true; while (waiting[i] && key)
key = test_and_set(&lock);
waiting[i] = false;
/* critical section */
j = (i + 1) % n;
while ((j != i) && !waiting[j])
j = (j + 1) % n;
if (j == i)
lock = false;
else
waiting[j] = false;
/* remainder section */
} while (true);
process queue를 순환적으로 검사하여 CS에 진입하고자 하는
프로세스를 발견하면 waiting[j] = false로 해서 진입을 하게 한다 (lock은 그대
로 유지).만약, 자기자신 이외에 CS를 진입하고자 하는 프로세스가 없다면 (if (j ==i)) lock을 풀어서 그 다음에 waiting[]이
true로 되는 프로세스가 어느때라도 진입할 수 있도록 한다
=> mutual exclusion, progress, bounded-waiting 모두 만족
Mutex locks
• 앞의 하드웨어 기법 (test_and_set)을 좀더 추상화
• 가장 단순한 방법
• acquire(), release()
• Atomic via hardware implementation
• Busy waiting
• Spinlock
Mutex locksacquire() { while (!available)
; /* busy wait */
available = false;;
}
release() {
available = true;
}
do {
acquire lock
critical section
release lock
remainder section
} while (true);
Semaphore• Busy waiting을 사용하지 않음
• S: semaphore variable, integer
• Counting semaphore: S >= 0
• Binary semaphore: S = 0 or 1
• wait(), signal()
• Should be implemented atomically
• 두 개의 프로세스가 동시에 wait()와 signal()을 동시에- 호출
• wait()
• CS에 진입 또는 어떤 상태를 기다려야만 하는 프로세스를 semaphore list에 삽입
• semaphore list에 있는 프로세스들은 wait 상태
• signal()
• semaphore list에 있는 프로세스 하나를 선택해서 ready 상태로
Semaphore
• P1 and P2 that require S1 to happen before S2
• P1: S1; signal(synch);
• P2: wait(synch); S2;
Semaphoretypedef struct{
int value;
struct process *list;
} semaphore;
wait(semaphore *S) {
S->value--;
if (S->value < 0) { add this process to S->list;
block();
}
}
signal(semaphore *S) {
S->value++;
if (S->value <= 0) { remove a process P from S->list;
wakeup(P);
}
}
Deadlock and Starvation
• Let S and Q be two semaphore initialized to 1
• P0: wait(S); wait(Q);… signal(S); signal(Q);
• P1: wait(Q); wait(S);… signal(Q); signal(S);
• P0가 wait(S)하고 있으면, P1이 signal(S)를해줘야 진행 가능, 그리고 P1이 wait(Q)하고 있으면 P0가 signal(Q)를 해줘야 진행 가능 => Deadlock!!
Classic problems of synchronization
• Bounded-buffer problem
• Readers and writers problem
• Dining philosophers problem
Bounded-buffer problem• n개의 버퍼
• 각 버퍼는 한개의 item을 저장
• 세 개의 세마포어
• mutex: 1로 초기화, 버퍼접근의 상호배제를 위해
• full: 0으로 초기화, 꽉찬 버퍼의 수를 기록 => empty 이면 버퍼에 데이터가 들어올 때까지 기다리는 세마포어
• empty: n으로 초기화, 비어있는 버퍼의 수를 기록 => full 이면 버퍼에 공간이 생길 때까지 기다리는 세마포어
■ The structure of the producer process
do {
... /* produce an item in next_produced */
...
wait(empty);
wait(mutex);
... /* add next produced to the buffer */
...
signal(mutex);
signal(full);
} while (true);
■ The structure of the consumer process
do {
wait(full);
wait(mutex);
... /* remove an item from buffer to next_consumed */
...
signal(mutex);
signal(empty);
... /* consume the item in next consumed */
... } while (true);
Readers-writers problem• 두 종류의 concurrent process에 의해서 데이터 (데이터베이스)가 공유
• Readers - 오로지 데이터를 읽어가기만 함
• Writers - 쓰기와 읽기를 모두 함
• 문제• 복수개의 reader는 동시에 읽어가게 할 수 있음
• 단 하나의 writer 만 접근할 수 있음
• 둘다 starvation 상태가 되어서는 안됨
• Shared data
• Data set
• Semaphore rw_mutex: 1로 초기화, writer 들간의 상호배제
• Semaphore mutex: 1로 초기화, read_count 접근의 상호배제
• Integer read_count: 0으로 초기화
Readers-writers problem• 하나의 writer만 CS에 진입
• 다른 writer나 reader는 대기
• CS에 아무런 reader나 다른 writer가 없을 경우에만 writer가 진입 가능
■ The structure of a writer process do {
wait(rw mutex);
... /* writing is performed */
...
signal(rw mutex);
} while (true);
■ The structure of a reader process do {wait(mutex);read_count++;if (read count == 1) wait(rw mutex); signal(mutex); .../* reading is performed */ ... wait(mutex);read count--;if (read count == 0) signal(rw mutex); signal(mutex); } while (true);
- read_count가 1이면 자신이 최초의 reader이므로 writer가 CS에 없을 경우에 (wait(rw_mutex)) 바로 진입- read_count가 1보다 크면 다른
reader들이 CS에 들어가 있으므로 바로 진입
- read_count가 0이면 CS에서 나온 마지막 reader, 따라서, writer의 진입
을 허가
다른 writer나 reader가 CS에 있으면 기다린다
Dining-philosophers problem
• 두 개의 젓가락이 있어야 식사가 가능
• 한번에 하나의 젓가락만 집을 수 있음
• 교재: 그림 6-14
• 동시에 모든 철학자가 자신의 왼쪽의 젓가락을 집으면?
• Deadlock
• 해결책• 두 개의 젓가락이 모두 사용가능 할때만 집는 것을 허용
• 비대칭 해결안홀수 번호 철학자는 왼쪽 젓가락을 먼저 집고, 짝수 번호 철학자는 오른쪽 젓가락을 먼저 집게 한다
• 최대 4명의 철학자만이 동시에 식탁에 앉도록 한다
Monitor• High-level abstraction
• Java, C#
• 공유자료와 그 공유자료에 접근하는 procedure를 하나의 구조체로 정의 => Monitor
• Monitor로 선언된 구조체를 갖는 프로세스들간에 자동적으로 공유자료 접근에 상호배제를 보장
• monitor monitor-name{ // shared variable declarations procedure P1() {…} procedure P2() {…} procedure P3() {…} initialization_code () {…} }
Monitor
Monitor
• condition variables
• 개발자가 원하는 동기화 메커니즘을 위해 사용
• condition x;
• x.wait(), x.signal() 제공
• 특정 자료를 공유하는 프로세스들끼리 동기화 할 수 있도록
Monitor
x에 의해 접근제어 되는 자료형을 기다리는 프로세스들
Monitor
• Solution to dining-philosophers monitor DiningPhilosophers {
enum { THINKING; HUNGRY, EATING) state [5] ;condition 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 left and right neighbors 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 () ; } }
initialization_code() { for (int i = 0; i < 5; i++) state[i] = THINKING;}
}
좌우 철학자가 모두 밥을 먹지 않을 경우, 진행
test(i) 결과 계속 HUNGRY 상태이면 대기
젓가락을 놓으면서 양옆 철학자가 만약 대기상태이면 진행시킨다
Monitor
• Each processor i
• DiningPhilosophers.pickup(i); EAT DiningPhilosophers.putdown(i)
• Monitor는 deadlock을 발생시키지 않고, 상호배제가 만족
• 하지만, starvation이 가능
• 이유는? HW #4
Pthread 동기화• #include <pthread.h>
pthread mutex_t mutex; pthread mutex_init(&mutex, NULL); pthread mutex_lock(&mutex); pthread mutex_unlock(&mutex);
• #include <semaphore.h>sem_t sem;sem_init(&sem, 0, 1); sem_wait(&sem); sem_post(&sem);
HW #5
• P.347 프로젝트 2