본문 바로가기
3학년 학사/운영체제

[운영체제] #9. 동기화(2)

by whiteTommy 2024. 12. 1.
반응형
더보기

목차

  • 동기화의 고전 문제 3가지
    1. Bounded-Buffer Problem
    2. Readers and Writers Problem
      • Solution 1
    3. Dining Philosophers Problem
      • Solution 1
      • Solution 2

 

동기화의 고전 문제 

1. Bounded-Buffer Problem

  • 문제 정의
    • 프로세스 동기화에서 자주 등장하는 고전적인 문제로, 생산자-소비자 문제(Producer-Consumer Problem) 라고도 한다.
    • N개의 아이템만 삽입할 수 있는 유한한 크기의 버퍼(Buffer)에서, 여러 생산자(Producer)와 소비자(Consumer) 가 동시에 접근하며 발생할 수 있는 Race Condition동기화 문제를 다룬다.
  • 문제 동작 과정

    • 생산자 (Producer)
      • 데이터를 생성하여 버퍼에 저장한다.
      • 작업 조건
        • 버퍼에 꽉 차있지 않으면, 데이터를 추가할 수 있음
        • 꽉 찼으면 대기해야 함
    • 소비자 (Consumer)
      • 버퍼에서 데이터를 가져와 처리한다.
      • 작업 조건
        • 버퍼에 데이터가 있으면 데이터를 가져갈 수 있음
        • 비어 있으면 대기해야 함
    • 문제 상황
      • Race condition : 여러 프로세스가 동시에 버퍼에 접근하여 데이터를 읽거나 쓸 때, 데이터 일관성이 깨질 수 있음
      • 동기화 문제
        • 생산자가 데이터를 추가하려고 할 때, 버퍼가 가득 차 있으면 대기해야 함
        • 소비자가 데이터를 가져가려고 할 때, 버퍼가 비어 있으면 대기해야 함
    • 구현
      • Buffer 의 구현
        • boolean buffer[n] 1차원 배열로 선언
        • buffer[0... n-1] = empty 로 초기화
      • 생산자 Operation
        • Buffer 배열 중, empty 인 index 를 찾아 full 로 바꿈
        • buffer[m] = full
      • 소비자 Opeartion
        • buffer 배열 중, full 인 index 를 찾아 empty 로 바꿈
        • buffer[m] = empty
      • 문제 해결
        • 생산자가 데이터를 추가하는 중에 소비자가 데이터를 가져가거나, 동시에 같은 슬롯에 접근하면 충돌 발생.
        • 이를 방지하기 위해 상호 배제(Mutex)와 세마포어(Semaphore)를 사용.
#include <stdio.h>
#include <pthread.h>
#include <semaphore.h>
#include <unistd.h>

#define BUFFER_SIZE 3

int buffer[BUFFER_SIZE];
int in = 0, out = 0;

sem_t empty; // 빈 슬롯을 추적
sem_t full;  // 채워진 슬롯을 추적
pthread_mutex_t mutex; // 상호 배제

void* producer(void* arg) {
    int item;
    for (int i = 0; i < 5; i++) {
        item = i + 1; // 생산한 데이터
        sem_wait(&empty); // 빈 슬롯 확인
        pthread_mutex_lock(&mutex); // Critical Section 시작

        buffer[in] = item;
        printf("Producer produced: %d\n", item);
        in = (in + 1) % BUFFER_SIZE;

        pthread_mutex_unlock(&mutex); // Critical Section 종료
        sem_post(&full); // 채워진 슬롯 증가

        sleep(1);
    }
    return NULL;
}

void* consumer(void* arg) {
    int item;
    for (int i = 0; i < 5; i++) {
        sem_wait(&full); // 채워진 슬롯 확인
        pthread_mutex_lock(&mutex); // Critical Section 시작

        item = buffer[out];
        printf("Consumer consumed: %d\n", item);
        out = (out + 1) % BUFFER_SIZE;

        pthread_mutex_unlock(&mutex); // Critical Section 종료
        sem_post(&empty); // 빈 슬롯 증가

        sleep(1);
    }
    return NULL;
}

int main() {
    pthread_t prod, cons;

    sem_init(&empty, 0, BUFFER_SIZE); // 초기 빈 슬롯: 버퍼 크기
    sem_init(&full, 0, 0);           // 초기 채워진 슬롯: 0
    pthread_mutex_init(&mutex, NULL);

    pthread_create(&prod, NULL, producer, NULL);
    pthread_create(&cons, NULL, consumer, NULL);

    pthread_join(prod, NULL);
    pthread_join(cons, NULL);

    sem_destroy(&empty);
    sem_destroy(&full);
    pthread_mutex_destroy(&mutex);

    return 0;
}

 

 

Bounded-Buffer Problem 세마포어

  • 문제 해결을 위한 세마포어
    • Empty:
      • 버퍼 내 빈 공간을 나타낸다
      • 생산자가 데이터를 추가할 때 감소(P(empty)), 소비자가 데이터를 제거할 때 증가(V(empty)).
      • 초기 값: n (버퍼의 총 크기).
    • Full:
      • 버퍼 내 채워진 데이터의 개수를 나타낸다
      • 소비자가 데이터를 제거할 때 감소(P(full)), 생산자가 데이터를 추가할 때 증가(V(full)).
      • 초기 값: 0 (비어있는 상태).
    • Mutex:
      • 버퍼 접근에 대한 Mutual Exclusion 를 보장한다.
      • 생산자와 소비자가 동시에 버퍼를 수정하지 못하도록 보호.
      • 초기 값: 1 (뮤텍스는 한 번에 한 프로세스만 접근 가능).

 

생산자 Process

do {
    produce an item in nextp;  // 데이터 생성

    P(empty);                // 빈 공간을 기다림
    P(mutex);                // Critical Section 보호

    add nextp to buffer;     // 버퍼에 데이터 추가

    V(mutex);                // Critical Section 종료
    V(full);                 // 채워진 데이터 개수 증가

} while (1);
  • 동작 과정
    • 생산자는 새로운 데이터를 생성.
    • P(empty):
      • 버퍼에 빈 공간이 없으면 대기.
      • 빈 공간이 있으면 감소.
    • P(mutex): 버퍼 접근 권한을 얻기 위해 뮤텍스 대기.
    • 데이터를 버퍼에 추가.
    • V(mutex): 버퍼에서 빠져나옴(Critical Section 종료).
    • V(full): 채워진 데이터의 개수를 증가.
    • 위 작업을 반복.

 

소비자 Process

do {
    P(full);                 // 데이터가 들어오기를 기다림
    P(mutex);                // Critical Section 보호

    remove an item from buffer to nextc; // 버퍼에서 데이터 가져오기

    V(mutex);                // Critical Section 종료
    V(empty);                // 빈 공간 개수 증가

    consume the item in nextc; // 데이터 소비
} while (1);

 

  • 동작 과정
    • P(full):
      • 버퍼에 데이터가 없으면 대기.
      • 데이터가 있으면 감소.
    • P(mutex): 버퍼 접근 권한을 얻기 위해 뮤텍스 대기.
    • 데이터를 버퍼에서 제거.
    • V(mutex): 버퍼에서 빠져나옴(Critical Section 종료).
    • V(empty): 빈 공간의 개수를 증가.
    • 데이터를 소비.
    • 위 작업을 반복.
  • 예시
    • 생산자 1:
      • 데이터 생성 → P(empty)로 빈 공간 확인 (empty = n-1).
      • 버퍼에 데이터 추가 → P(mutex)로 뮤텍스 잠금.
      • V(mutex) → Critical Section 종료.
      • V(full) → 채워진 슬롯 증가 (full = 1).
    • 소비자 1:
      • P(full) → 데이터가 있는지 확인 (full = 0).
      • P(mutex)로 뮤텍스 잠금 후 데이터 제거.
      • V(mutex) → Critical Section 종료.
      • V(empty) → 빈 공간 증가 (empty = n).

 

2. Readers-Writers Problem

  • 문제 정의
    • 여러 Reader(읽기 프로세스)와 Writer(쓰기 프로세스)가 동일한 데이터에 접근하려 할 때 데이터의 무결성과 동기화를 유지하는 문제.
    • 목표:
      1. 여러 Reader는 동시에 데이터를 읽을 수 있음.
      2. Writer는 단독으로 데이터를 수정해야 함 (읽거나 쓰는 중에 다른 작업 불가).
      3. Reader와 Writer가 동시에 데이터에 접근하면 안 됨.

 

Readers-Writers Problem Solution 1

  • 문제 해결을 위한 자료구조와 세마포어
    • int Readcount:
      • 현재 데이터를 읽고 있는 Reader의 수를 저장.
      • 첫 번째 Reader가 진입하면 Writer를 차단.
    • Semaphore Wrt:
      • Writer 간의 동기화를 보장.
      • Writer가 작업 중일 때 Reader와 다른 Writer의 접근을 차단.
    • Semaphore Mutex:
      • Readcount 와 wrt 에의 접근이 원자적으로 수행됨을 보장하기 위한 세마포어
  • 초기값
    • Mutex = 1: Reader가 Readcount를 안전하게 수정 가능.
    • Wrt = 1: Writer의 접근 제어.
    • Readcount = 0: 초기에는 Reader가 없음.

 

Writer Process

P(wrt);    // Writer가 진입. 다른 Writer와 Reader 차단
// Critical Section
writing is performed;  // 데이터 쓰기 작업 수행
V(wrt);    // Writer가 작업 완료. 접근 해제
  • 작동 원리
    • Writer가 P(wrt)를 호출하여 Critical Section에 진입.
    • 데이터 쓰기 작업이 끝나면 V(wrt)를 호출하여 Critical Section을 나감.

 

Reader Process

P(mutex);          // Readcount에 대한 상호 배제 보호
readcount++;       // Reader 수 증가
if (readcount == 1)
    P(wrt);        // 첫 번째 Reader가 진입 시 Writer 차단
V(mutex);          // Readcount 수정 완료

// Critical Section
reading is performed;  // 데이터 읽기 작업 수행

P(mutex);          // Readcount에 대한 상호 배제 보호
readcount--;       // Reader 수 감소
if (readcount == 0)
    V(wrt);        // 마지막 Reader가 나가면 Writer 허용
V(mutex);          // Readcount 수정 완료
  • 작동 원리
    • P(mutex)로 Readcount 보호.
    • Readcount++: 첫 번째 Reader가 진입하면 P(wrt)를 호출하여 Writer를 차단.
    • Critical Section에서 데이터를 읽음.
    • Reader가 작업을 끝내고 나가면:
      • Readcount--:
        • 마지막 Reader가 나가면 V(wrt)를 호출하여 Writer를 허용.
  • 작동 예시
    • 초기값
      • Readcount = 0, Mutex = 1, Wrt = 1
    • 동작
      • Reader 1 진입:
        • P(mutex) → Readcount = 1.
        • 첫 Reader이므로 P(wrt)로 Writer 차단.
        • Critical Section에서 읽기 작업 수행.
        • V(mutex).
      • Reader 2 진입:
        • P(mutex) → Readcount = 2.
        • 이미 Writer는 차단되었으므로 P(wrt) 불필요.
        • Critical Section에서 읽기 작업 수행.
        • V(mutex).
      • Reader 1 종료:
        • P(mutex) → Readcount = 1.
        • Writer는 여전히 차단 상태.
        • V(mutex).
      • Reader 2 종료:
        • P(mutex) → Readcount = 0.
        • 마지막 Reader이므로 V(wrt)로 Writer를 허용.
        • V(mutex).
      • Writer 진입:
        • P(wrt) → Writer가 Critical Section에 진입.
        • Writer 작업 수행 후 V(wrt)로 종료.
  • 문제점
    • Writer 의 Starvation
      • Readcount == 0 일 때만, V(wrt) 가 수행되어 P(wrt) 로 대기하고 있던 Writer 가 수행할 수 있음
      • 첫 번째 Reader (Readcount == 1) 가 P(wrt) 만 통과하면, 다른 Reader 들은 P(mutex)에 대한 P(mutex) 만 기다리면, 언제든지 수행할 수 있기 때문에 Writer 와 상관없이 진입할 수 있음
      • 여러 Reader 들이 계속해서 진입할 경우, Readcount 는 0까지 떨어지지 않을 수 있음
  • 해결 (1)
    • Writers Preference
      • Writer가 데이터를 수정할 때 우선권을 가짐.
    • 추가 변수
      • int writecount
        • 현재 Writer의 수를 추적하여 우선권을 부여.
    • 문제
      • Reader가 굶주릴(Starvation) 가능성이 있음.
    • 구현
// Reader Process
P(mutex);            // Readcount를 안전하게 수정하기 위해 뮤텍스 보호
while (writecount > 0)  // Writer가 대기 중이면 진입 대기
    wait();
readcount++;         // 현재 Reader 수 증가
if (readcount == 1)  // 첫 번째 Reader가 진입하면 Writer를 차단
    P(wrt);          
V(mutex);            // Readcount 수정 완료

// Critical Section
reading is performed;  // 데이터 읽기 작업 수행

P(mutex);            // Readcount를 안전하게 수정하기 위해 뮤텍스 보호
readcount--;         // Reader 수 감소
if (readcount == 0)  // 마지막 Reader가 나가면 Writer 허용
    V(wrt);          
V(mutex);            // Readcount 수정 완료

----------------------------------------------------------------------
// Writer Process
P(mutex);            // writecount를 안전하게 수정하기 위해 뮤텍스 보호
writecount++;        // Writer 수 증가
V(mutex);

P(wrt);              // Writer가 Critical Section에 진입. Reader 차단
// Critical Section
writing is performed;  // 데이터 쓰기 작업 수행
V(wrt);

P(mutex);            // writecount를 안전하게 수정하기 위해 뮤텍스 보호
writecount--;        // Writer 수 감소
if (writecount == 0)
    signal();        // 대기 중인 Reader 허용
V(mutex);

 

  • 해결(2)
    • Fair Solution
      • Reader와 Writer 중 먼저 요청한 프로세스에 우선권을 부여.
      • Reader와 Writer가 공정하게 실행되므로 Starvation 문제를 방지.
    • 필요한 자료구조
      • Queue: Reader와 Writer 요청을 관리.
    • 구현 아이디어
      • Reader와 Writer가 요청을 Queue에 삽입.
      • Queue에서 요청 순서대로 Critical Section에 접근.
      • 한 번에 하나의 Writer 또는 여러 Reader가 접근 가능.
    • 구현
#include <stdio.h>
#include <pthread.h>
#include <semaphore.h>

#define NUM_READERS 5
#define NUM_WRITERS 3

sem_t queue;       // 공정한 순서를 보장하기 위한 세마포어
sem_t wrt;         // Writer 접근 제어
sem_t mutex;       // Reader 수 조작 보호

int readcount = 0; // 현재 읽고 있는 Reader 수

// Reader 프로세스 함수
void* reader(void* arg) {
    int id = *((int*)arg);

    while (1) {
        sem_wait(&queue);  // 공정한 순서를 보장하기 위해 대기
        sem_wait(&mutex);  // Reader 수를 안전하게 증가
        readcount++;
        if (readcount == 1)
            sem_wait(&wrt);  // 첫 번째 Reader가 Writer를 차단
        sem_post(&mutex);  // Reader 수 수정 완료
        sem_post(&queue);  // 다음 프로세스에 접근 허용

        // Critical Section (읽기 작업)
        printf("Reader %d is reading\n", id);

        sem_wait(&mutex);  // Reader 수를 안전하게 감소
        readcount--;
        if (readcount == 0)
            sem_post(&wrt);  // 마지막 Reader가 나가면 Writer 허용
        sem_post(&mutex);  // Reader 수 수정 완료
    }
    return NULL;
}

// Writer 프로세스 함수
void* writer(void* arg) {
    int id = *((int*)arg);

    while (1) {
        sem_wait(&queue);  // 공정한 순서를 보장하기 위해 대기
        sem_wait(&wrt);    // Writer가 Critical Section에 진입
        sem_post(&queue);  // 다음 프로세스에 접근 허용

        // Critical Section (쓰기 작업)
        printf("Writer %d is writing\n", id);

        sem_post(&wrt);    // Writer 작업 완료
    }
    return NULL;
}

int main() {
    pthread_t r_threads[NUM_READERS], w_threads[NUM_WRITERS];
    int r_ids[NUM_READERS], w_ids[NUM_WRITERS];

    // 세마포어 초기화
    sem_init(&queue, 0, 1);  // 하나씩 순서를 보장
    sem_init(&wrt, 0, 1);    // Writer 접근 제어
    sem_init(&mutex, 0, 1);  // Reader 수 조작 보호

    // Reader 스레드 생성
    for (int i = 0; i < NUM_READERS; i++) {
        r_ids[i] = i + 1;
        pthread_create(&r_threads[i], NULL, reader, &r_ids[i]);
    }

    // Writer 스레드 생성
    for (int i = 0; i < NUM_WRITERS; i++) {
        w_ids[i] = i + 1;
        pthread_create(&w_threads[i], NULL, writer, &w_ids[i]);
    }

    // 스레드가 종료되지 않도록 대기
    for (int i = 0; i < NUM_READERS; i++) {
        pthread_join(r_threads[i], NULL);
    }
    for (int i = 0; i < NUM_WRITERS; i++) {
        pthread_join(w_threads[i], NULL);
    }

    // 세마포어 해제
    sem_destroy(&queue);
    sem_destroy(&wrt);
    sem_destroy(&mutex);

    return 0;
}

 

  • 동작 원리
    • queue 세마포어:
      • 모든 Reader와 Writer의 공정성을 보장.
      • Reader와 Writer가 FIFO 순서로 실행되도록 제어.
    • mutex 세마포어:
      • readcount 변수를 보호하여 Race Condition을 방지.
      • Reader 수를 안전하게 증가/감소.
    • wrt 세마포어:
      • Writer 간의 상호 배제 및 Reader와 Writer의 동기화를 보장.
  • 결과
    • Reader와 Writer의 공정성:
      • Reader와 Writer는 FIFO 순서로 실행됨
      • Writer가 대기 중이라면 Reader는 작업을 마친 후 Writer에 우선권을 부여.
      • Writer와 Reader의 작업이 공정하게 수행됨.
  • 실행 예시
Reader 1 is reading
Reader 2 is reading
Reader 3 is reading
Reader 4 is reading
Reader 5 is reading
Writer 1 is writing
Reader 1 is reading
Writer 2 is writing
Reader 2 is reading
Writer 3 is writing
...

 

 

3. Dining-Philosophers Problem

  • 문제 정의
    • 5명의 철학자가 원탁에 앉아 있으며, 각 철학자 사이에는 젓가락이 하나씩 놓여 있음.
    • 고전적인 Concurrency Method
    • 철학자는 생각(thinking)하거나, 먹기(eating)를 수행.
    • 젓가락이 5개 뿐
      • 이웃한 젓가락만 집을 수 있음
      • 두 젓가락을 모두 집어야 식사 가능
      • 식사를 하고 난 다음에야 두 젓가락을 모두 내려놓을 수 있음
    • Deadlock 과 Starvation 이 발생하는 경우
      • 모두 자신의 오른쪽 젓가락을 집었을 경우
        • 이로 인해 모든 철학자가 젓가락을 기다리면서 무한 대기 상태에 빠짐.

Dining-Philosophers Problem Solution 1

  • 단순히 젓가락을 집는 것에 대한 동기화를 부여하는 방법
    • 모든 철학자가 자신의 왼쪽 또는 오른쪽 젓가락부터 집도록 한다.
    • boolean waiting[n] = 1
  • 세마포어
    • chopstic[5] = 1: 각각의 젓가락에 대한 동기화 관리

 

철학자 Process

do {
    think();                                      // 생각
    P(chopstick[i]);                              // 왼쪽 젓가락 집기
    P(chopstick[(i + 1) % 5]);                    // 오른쪽 젓가락 집기
    eat();                                       // 먹기
    V(chopstick[i]);                              // 왼쪽 젓가락 놓기
    V(chopstick[(i + 1) % 5]);                    // 오른쪽 젓가락 놓기
} while (1);
  •  문제점
    • Deadlock 발생 가능:
      • 모든 철학자가 동시에 젓가락을 집으면, 각자 한 개의 젓가락을 가지고 대기 상태에 빠짐.
  • 해결
    • 한 번에 최대 4명의 철학자만 식사에 참여 가능.
    • 양 쪽 젓가락이 모두 사용 가능할 때만 젓가락을 집도록 함
    • 홀수 번호 철학자는 왼쪽 젓가락부터 잡고, 짝수 번호 철학자는 오른쪽 젓가락부터 잡음
  • 위의 해결방안들은 Starvation 까지 해결해주지는 못함
    • 각각의 방안에 대해 Starvation 에 대한 고려를 추가할 수 있음
      ex) 한 차례 굶은 철학자에게 우선권을 줌

 

Dining-Philosophers Problem Solution 2

 

  • 문제 해결 접근 방식
    • 철학자가 자신의 상태와 양쪽 젓가락의 상태를 확인 후, 양쪽 젓가락을 집거나 대기.
    • 동시에 두 젓가락을 집을 수 있도록 상태와 동기화를 관리.
  • 사용되는 자료구조
    • State 배열:
      • State[5]: 각 철학자의 현재 상태를 저장.
        • THINKING: 생각 중.
        • HUNGRY: 젓가락을 잡고 싶어함.
        • EATING: 젓가락을 잡고 먹는 중.
    • Mutex: 젓가락을 집거나 놓는 수행을 Critical Section 으로 관리하기 위한 세마포어. (초기값 : 1)
    • Self 배열:
      • Self[5] : 철학자 각각이 젓가락 두 개를 집기를 기다리는 세마포어 (초기값 : 0)
        • 철학자 i 가 HUNGRY 상태이더라도, 다른 젓가락 하나를 사용할 수 없을 경우 Waiting 을 하기 위한 세마포어

 

철학자 Process

do {
    think();                 // 생각
    take_chopsticks(i);      // 젓가락을 집기
    eat();                   // 먹기
    put_chopsticks(i);       // 젓가락을 내려놓기
} while (1);

 

 

 

void take_chopsticks(int i) {
    P(mutex);                     // 상태 변경 및 테스트 보호
    state[i] = HUNGRY;            // 철학자 상태를 HUNGRY로 설정
    test(i);                      // 자신이 EATING으로 전환 가능한지 테스트
    V(mutex);                     // 상태 변경 작업 완료
    P(self[i]);                   // 자신이 EATING 상태가 될 때까지 대기
}

 

  • 동작 과정
    • 목적: 젓가락을 잡기 전 조건 확인 및 대기.
    • 구현 논리:
      1. Mutex를 통해 동기화 시작:
        • state[i]를 HUNGRY로 설정.
        • test(i)를 호출하여 철학자가 식사 가능한 상태인지 확인.
      2. 식사 불가능한 경우: self[i] 세마포어를 통해 대기 상태로 전환.
      3. 식사 가능 상태: self[i] 신호를 받아 EATING 상태로 진입.

 

void put_chopsticks(int i) {
    P(mutex);                     // 상태 변경 및 테스트 보호
    state[i] = THINKING;          // 철학자 상태를 THINKING으로 설정
    test(LEFT);                   // 왼쪽 철학자가 EATING 상태로 전환 가능한지 테스트
    test(RIGHT);                  // 오른쪽 철학자가 EATING 상태로 전환 가능한지 테스트
    V(mutex);                     // 상태 변경 작업 완료
}
  • 동작 과정
    • 목적: 식사를 마치고 젓가락을 내려놓음.
    • 구현 논리:
      1. Mutex를 통해 동기화 시작:
        • 철학자의 상태를 THINKING으로 전환.
        • 왼쪽(LEFT)과 오른쪽(RIGHT) 철학자의 상태를 확인.
      2. test() 호출:
        • 왼쪽과 오른쪽 철학자가 젓가락을 사용할 수 있다면 신호를 보내 EATING 상태로 전환.

void test(int i) {
    if (state[i] == HUNGRY &&         // 현재 철학자가 HUNGRY 상태이고
        state[LEFT] != EATING &&      // 왼쪽 철학자가 EATING 중이 아니며
        state[RIGHT] != EATING) {     // 오른쪽 철학자가 EATING 중이 아닐 때
        state[i] = EATING;            // 철학자 상태를 EATING으로 변경
        V(self[i]);                   // 철학자에게 신호를 보내 EATING 상태로 전환
    }
}
  • 동작 과정
    • 목적: 젓가락 상태를 확인하고 철학자가 식사 가능한지 결정.
    • 구현 논리:
      • 철학자가 HUNGRY 상태이고, 왼쪽과 오른쪽 철학자가 EATING 중이 아닐 경우:
        • 철학자의 상태를 EATING으로 전환.
        • 철학자 자신에게 신호를 보내 대기에서 해제.

 

  • 전체적인 동작 과정
    • 철학자가 식사를 시작하는 경우:
      • take_chopsticks(i) 호출.
      • 상태를 HUNGRY로 변경 후, 좌우 젓가락 상태 확인.
      • 좌우 젓가락이 사용 가능하면 식사 시작(EATING 상태).
    • 철학자가 식사를 끝내는 경우:
      • put_chopsticks(i) 호출.
      • 상태를 THINKING으로 변경 후, 좌우 철학자의 상태 확인.
      • 좌우 철학자가 식사 가능하다면 신호를 보내 식사 시작.
  • 해설
    • 철학자 좌우 젓가락이 사용 가능할 때만 Critical Section 에 진입함
      • i 번째 철학자가 식사를 하기 위해서는 i-1 과 i+1 철학자가 EATING 상태가 아니어야 함
  • check 요소
    • Data Consistency: 상태(State) 배열과 세마포어를 통해 데이터 일관성 보장.
    • Deadlock 방지: 철학자가 식사 가능한 경우에만 Critical Section에 진입하도록 설계.
    • Starvation 가능성: 해결되지 않을 수 있음. Starvation 방지 메커니즘 추가 가능.
    • Concurrency: 여러 철학자가 동시에 작업을 수행 가능.

 

 

반응형