본문 바로가기
혼자 공부하는 것들/운영체제

[운영체제]Producer/Consumer 실습 + 세마포어 변수 사용

by applepick 2020. 10. 2.
반응형

생산자-소비자 문제란?

여러 개의 프로세스를 어떻게 동기화할 것인가에 관한 고전적인 문제이다. 한정 버퍼 문제(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++의 주석을 지우면 자원 공유 때문에 상호 배제가 필요하다.

버퍼라는 배열은 공유하지만 각 요소를 접근하는 것은 다르기 때문에 상호 배제가 필요 없다.

반응형

댓글