생산자-소비자 문제란?
여러 개의 프로세스를 어떻게 동기화할 것인가에 관한 고전적인 문제이다. 한정 버퍼 문제(bounded-buffer problem)라고도 한다. 유한한 개수의 물건(데이터)을 임시로 보관하는 보관함(버퍼)에 여러 명의 생산자들과 소비자들이 접근한다. 생산자는 물건이 하나 만들어지면 그 공간에 저장한다. 이때 저장할 공간이 없는 문제가 발생할 수 있다. 소비자는 물건이 필요할 때 보관함에서 물건을 하나 가져온다. 이 때는 소비할 물건이 없는 문제가 발생할 수 있다.
세마포어란(Semaphore)?
세마포어(Semaphore)는 두 개의 원자적 함수로 조작되는 정수 변수로서, 멀티프로그래밍 환경에서 공유 자원에 대한 접근을 제한하는 방법으로 사용된다. 이는 철학자들의 만찬 문제의 고전적인 해법이지만 모든 교착 상태를 해결하지는 못한다.
producer_comsumer.c를 세마포어를 사용하여 동작하도록 실행해보자.
producer_comsumer.c
#include <semaphore.h>
#include <pthread.h>
#include <stdio.h>
#define TRUE 1
#define FALSE 0
#define N 100 // buffer size
#define ITEMS 100000 // # of items
typedef sem_t semaphore;
semaphore mutex;
semaphore empty;
semaphore full;
#define down(A) sem_wait(A)
#define up(A) sem_post(A)
int produce_item();
void consume_item(int consumer_id, int item);
void insert_item(int item);
int remove_item();
void producer(void);
void* consumer(void *cid);
int buff[N];
int count = 0;
int rear = -1;
int front = -1;
int main()
{
int i;
pthread_t consumer_thr;
pthread_attr_t attr;
void *status;
int j;
// Initialize
sem_init(&mutex, 0, 1);
sem_init(&empty, 0, N);
sem_init(&full, 0, 0);
for (i = 0; i < N; i++)
buff[i] = 0;
count = 0;
pthread_attr_init(&attr);
pthread_attr_setscope(&attr, PTHREAD_SCOPE_SYSTEM); int cid = 0;
// Create a child thread for the consumer 스레드 스케줄링
pthread_create(&consumer_thr, &attr, consumer, &cid);//자식스레드 생성
producer();
pthread_join(consumer_thr, &status);
}
void producer(void)
{
int item;
static int nitem = 0;
while (nitem < ITEMS) {//10만번
item = produce_item();
down(&empty);
// down(&mutex);
insert_item(item);
// up(&mutex);
up(&full);
nitem++;
}
// Insert 'END' mark
down(&empty);
// down(&mutex);
insert_item(-1); // -1 means 'END' 끝났다.
// up(&mutex);
up(&full);
}
void* consumer(void *cid)
{
int consumer_id = *(int *) cid;
int item;
while (TRUE) {
down(&full);
// down(&mutex);
item = remove_item();
// up(&mutex);
up(&empty);
if (item == -1) // if 'END' mark 끝났다.
break;
consume_item(consumer_id, item);
}
pthread_exit(NULL);
}
int produce_item()
{
static int item = 0; return item++;
}
void consume_item(int consumer_id, int item)
{
// Just consume
printf("Consumer %d consumes: %d\n", consumer_id, item);
}
void insert_item(int item)
{
rear = (rear + 1) % N;
buff[rear] = item;
// count++;
return;
}
int remove_item()
{
int item;
front = (front + 1) % N;
item = buff[front];
// count--;
return item;
}
1. 버퍼의 크기는 얼마인가?
- 100이다.
2. 사용하는 세마포어 변수들은 무엇인가?
- mutex, empty, full 3가지가있다.
3. 버퍼가 가득 차 있는 것을 나타내는 조건은 무엇인가?
- empty=0 일 때이다.
버퍼가 가득 차 있을 때
producer가 버퍼에 insert_item()을 수행하지 않도록 하는 메커니즘은 무엇인가?
- down(&empty);
버퍼에 다시 빈 공간이 생겼을 때 producer가 insert_item()을 수행할 수 있도록 하기
위해, consumer는 어떤 동작을 수행하는가?
-up(&empty);해주면 잠들어있던 프로듀스가 깨어난다.
4. 프로그램에서 주석처리(//) 된 down(mutex)와 up(mutex)는 필요한가? 즉, mutex 세마
포어 변수를 사용하여 상호 배제를 해야 할 공유 데이터(변수)가 있는가? 주석처리된 프
로그램과 그렇지 않은 프로그램의 실행 결과에 차이가 있는지 설명하시오.
- 차이가 없습니다. 상호 배제가 이경우에 필요하지 않다. 동시에 접속할 일이 없다.
count++의 주석을 지우면 자원 공유 때문에 상호 배제가 필요하다.
버퍼라는 배열은 공유하지만 각 요소를 접근하는 것은 다르기 때문에 상호 배제가 필요 없다.
'혼자 공부하는 것들 > 운영체제' 카테고리의 다른 글
Web Server 실습 +Dispatcher 사용 (6) | 2020.10.02 |
---|---|
[운영체제]Producer/Consumer 실습 - 2 상호배제 (0) | 2020.10.02 |
[운영체제] Race Condition, Mutual Exclusive(상호배제) 실습 (2) | 2020.10.02 |
[운영체제] 스레드(Thread) + 실습을 통해 직접 깨우치기! 프로세스와의 차이점? (2) | 2020.09.28 |
[운영체제] 프로세스 상태 +실습을 통해 직접 깨우치기! (0) | 2020.09.28 |
댓글