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

Web Server 실습 +Dispatcher 사용

by applepick 2020. 10. 2.
반응형

다중스레드 웹 서버에서 작업을 분배받는 과정을 producer-consumer 모델로 만
들어 본다. Dispatcher thread는 작업을 worker thread들에게 배분하며, 이때 한 개의 원형 큐가 버퍼로써 사용되게 설계해볼 것이다.

 

Dispatcher란?

CPU의 제어권을 STS(Short-Term Scheduling)에 의하여 선택된 Process에게 넘겨주는 모듈을 말한다.

인터럽트 또는 시스템 호출의 결과로 커널 모드에서 제어를 받는다. 디스패처는 모든 프로세스 전환 중에 호출되므로 가능한 한 빨라야한다.


요구사항

1. Dispatcher는 producer로써, 원형 큐(버퍼)에 작업 내용을 기록한다.
2. Worker는 consumer로써, 원형 큐(버퍼)로부터 작업 내용을 읽는다.
3. 2개의 worker thread가 작업한다.(dispatcher는 1개)
4. Dispatcher가 원형 큐에 전달할 작업 내용은 0, 1, 2, …, 99999이다.
5. 모두 전달한 다음, 더 이상의 작업이 없다는 의미로 -1을 두 번 원형 큐에 보낸다.
6. Worker는 전달 받은 내용을 단지 화면에 출력한다. -1을 받으면 스레드를 종료한다.
7. Worker는 다음과 같이 출력한다: (Worker worker_id: job_id)
Worker 1: 1 (Worker 1의 출력)
Worker 2: 2 (Worker 2의 출력)
Worker 2: 3 (Worker 2의 출력)

소스코드

#include <semaphore.h>
#include <pthread.h>
#include <stdio.h>
#define TRUE 1
#define FALSE 0
#define N 100
#define N_ITEMS 100000
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 worker_id, int item);
void insert_item(int item);
int remove_item();
void dispatcher(void);
void* worker(void *wid);
int buff[N];
int count = 0;
int rear = -1;
int front = -1;
int main()
{
	int i;
 	pthread_t t1, t2;
 	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);
 	int w1 = 1;
 	int w2 = 2;
 	pthread_create(&t1, &attr, worker, &w1);
 	pthread_create(&t2, &attr, worker, &w2);
 	dispatcher(); pthread_join(t1, &status);
 	pthread_join(t2, &status);
}
void dispatcher(void)
{
        int item;
        static int nitem = 0;
         while (nitem < N_ITEMS) {
         item = produce_item();
         //down(&empty);
        down(&mutex);
        insert_item(item);
         //up(&full);
        up(&mutex);
        nitem++;
	 }
	//down(&empty);
	down(&mutex);
	insert_item(-1);
	//up(&full);
	up(&mutex);
}
void* worker(void *wid)
{
        int consumer_id = *(int *) wid;
        int item;
        while(TRUE){
        //down(&full);
        down(&mutex);
        item = remove_item();
        //up(&empty);
        up(&mutex);
        if(item == -1){
                break;
        }
        consume_item(consumer_id, item);
        }
        pthread_exit(NULL);
}
int produce_item()
{
 	static int item = 0;
 	return item++;
}
void consume_item(int worker_id, int item)
{
 	// Just consume
 	printf("Worker %d: %d\n", worker_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;
}

작성 코드에 대한 설명

int main()

- 쓰래드를 생성해주고, 버퍼를 초기화 시켜준다. 세마포어 함수를통해 크리티컬리젼이 일어나지 않도록 방지해준다.

void dispatcher(void)

- N_ITEMS만큼 while문을 반복시켜 produce_item();을 통해 item에 증가된 값을 저장한다. producer기능을 한다. 원형 큐(버퍼)에 기록해주는 함수이다.

void* worker(void *wid)

- consumer기능을한다. 원형 큐(버퍼)로부터 읽어오는 함수이다. consumer_id를 만들어줘 wid의 메모리크기만큼 할당해준다. while문을 계속 반복시키면서 item에 지울 item을 대입하고 consumer_iditem을 출력해준다.

int produce_item()

- item1증가시켜주는 함수이다.

void consume_item(int worker_id, int item)

- 일하는 workerconsumer_id를 받고 item을 출력해줍니다.

void insert_item(int item)

- 원형 큐(버퍼)item을 삽입해주는 함수입니다.

int remove_item()

- 해당 item을 원형 큐(버퍼)에서 지워주는 역할을 하는 함수입니다.

실행결과에 대한 설명 ,실행화면 캡쳐

1) ./webserver을 사용하면 아래와같이 출력된다. work 1 work2를 상호배제를 하여 크리티컬리젼이 일어나지 않도록 하였습니다.

 

2)

./webserver | grep "Worker 1" | wc -l

./webserver | grep "Worker 2" | wc -l

worker 1worker 2가 출력한 개수를 출력해줍니다. 할당되는 값은 항상 유동적이기 때문에 값이 계속 변화하게 됩니다.

반응형

댓글