생산자 소비자 문제

topics 700-컴퓨터과학 704 운영체제
types 이론 학습
tags

생산자 소비자 문제

여러 개의 프로세스를 어떻게 동기화할 것인가에 관한 고전적인 문제다. **한정 버퍼 문제(bounded-buffer problem)**라고도 한다.

해결 방법에는 뮤텍스세마포어가 있다.

뮤텍스 (Mutex)

Pasted image 20240401120816.png

각각 단독으로 상호 배제될 수 있게 하여 동시 접근을 제한한다. 해당 뮤텍스 객체를 동시에 사용이 불가능하다.

세마포어 (Semaphore)

Pasted image 20240401121001.png

최대 허용치만큼 사용자가 접근할 수 있다. 각각 인덱스에서 자원을 사용 중인지 확인하고 자원을 사용하지 않을 때 접근이 가능하다. 사용 중일 때는 특정 값으로 변경하여 사용 중임을 알려야 한다.

세마포어를 이용한 구현

더 효율적인 세마포어를 이용한 알고리즘이다.

#include <stdio.h>
#include <pthread.h>
#include <semaphore.h>

#define BUFFER_SIZE 10

typedef int item;
item buffer[BUFFER_SIZE];
int in = 0;
int out = 0;

sem_t empty;
sem_t full;
pthread_mutex_t mutex;

void *producer(void *param) {
    item newItem;
    while (1) {
        // 새로운 아이템 생성
        newItem = produce_item();

        sem_wait(&empty); // 빈 공간에 대한 세마포어 감소
        pthread_mutex_lock(&mutex); // 임계 영역 진입

        // 아이템을 버퍼에 추가
        buffer[in] = newItem;
        in = (in + 1) % BUFFER_SIZE;

        pthread_mutex_unlock(&mutex); // 임계 영역 탈출
        sem_post(&full); // 채워진 공간에 대한 세마포어 증가
    }
}

void *consumer(void *param) {
    item consumedItem;
    while (1) {
        sem_wait(&full); // 채워진 공간에 대한 세마포어 감소
        pthread_mutex_lock(&mutex); // 임계 영역 진입

        // 버퍼에서 아이템을 가져옴
        consumedItem = buffer[out];
        out = (out + 1) % BUFFER_SIZE;

        pthread_mutex_unlock(&mutex); // 임계 영역 탈출
        sem_post(&empty); // 빈 공간에 대한 세마포어 증가

        // 아이템 소비
        consume_item(consumedItem);
    }
}

int main() {
    pthread_t tid1, tid2;
    pthread_mutex_init(&mutex, NULL);
    sem_init(&empty, 0, BUFFER_SIZE);
    sem_init(&full, 0, 0);

    pthread_create(&tid1, NULL, producer, NULL);
    pthread_create(&tid2, NULL, consumer, NULL);

    pthread_join(tid1, NULL);
    pthread_join(tid2, NULL);

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

    return 0;
}

핵심 포인트

세마포어 역할
empty 버퍼의 빈 공간 개수를 추적. 초기값은 BUFFER_SIZE
full 버퍼의 채워진 공간 개수를 추적. 초기값은 0
mutex 임계 영역 보호

동작 흐름

Producer:

  1. sem_wait(&empty): 빈 공간이 있을 때까지 대기
  2. pthread_mutex_lock(&mutex): 임계 영역 진입
  3. 버퍼에 아이템 추가
  4. pthread_mutex_unlock(&mutex): 임계 영역 탈출
  5. sem_post(&full): 채워진 공간 개수 증가

Consumer:

  1. sem_wait(&full): 채워진 공간이 있을 때까지 대기
  2. pthread_mutex_lock(&mutex): 임계 영역 진입
  3. 버퍼에서 아이템 가져옴
  4. pthread_mutex_unlock(&mutex): 임계 영역 탈출
  5. sem_post(&empty): 빈 공간 개수 증가

관련 문서