본문 바로가기

etc..

[MFC]쓰레드와 세마포어, 뮤텍스를 이용한 생산자-소비자 문제

유닉스랑 리눅스의 pthread만 쓰다가
과제가 나왔길래 리눅스로 할래 MFC로 할래 하길래 이번 기회에 MFC 쓰레드도 공부할겸
MFC로 하기로 했다.

MFC 쓰레드를 이용하는 것이 처음이라서 먼저 서너시간쯤 MFC쓰레드에 관해 살펴보다가 짰다.
처음에 win 32api쓰레드와 MFC 쓰레드가 헷갈려서 찾아보다가 결론은 두 개는 거의 비슷하고
MFC 쓰레드는 win32 api 쓰레드를 wrapping 한 것이라고 S모씨가 알려주었다.
아 다만 쓰레드 생성 함수가 약간 다르다.

MFC는 쓰레드가 Worker 쓰레드와 user interface 쓰레드로 나뉘고 각각의 쓰임새가 있다.
처음에 뭘 쓸까, 무슨 차이일까 고민하다가 찾아보니
UI Thread는 사용자 메시지 루프를 가지고 있는(즉 어떤 메시지가 날라오면 일하는.. )쓰레드이고..
Worker Thread는, 보통 오래 걸리는 작업이나 무한루프를 가지는 작업을 하는 사용자 정의 함수의 경우 사용.  UI Thread를 사용하려면, CWinThread 파생 클래스를 만들어 사용한다.
라는 똑같은 결론들만 있길래  좀 더 알아보니

심민조 ( [민조] I saw U.. ) 님의 말 :
흠 잠시만
심민조 ( [민조] I saw U.. ) 님의 말 :
ㅎㅎㅎ
심민조 ( [민조] I saw U.. ) 님의 말 :
단순히 설명을 보자면
심민조 ( [민조] I saw U.. ) 님의 말 :
쓰레드의 개념은 같은데
심민조 ( [민조] I saw U.. ) 님의 말 :
별개의 존재로 생성되서 그리로 메시지가 전달되느냐
심민조 ( [민조] I saw U.. ) 님의 말 :
아니면
심민조 ( [민조] I saw U.. ) 님의 말 :
그냥 현재 app의 백그라운드에서
심민조 ( [민조] I saw U.. ) 님의 말 :
돌아가게 되느냐
심민조 ( [민조] I saw U.. ) 님의 말 :
뭐 그런차이인듯한데
방호남 ( 최-악이다 ) 님의 말 :
네 그런거 같아요
심민조 ( [민조] I saw U.. ) 님의 말 :
좀더 자세히보면
심민조 ( [민조] I saw U.. ) 님의 말 :
사실상 OS에서는
심민조 ( [민조] I saw U.. ) 님의 말 :
둘다 그냥 쓰레드로 인식하지만
심민조 ( [민조] I saw U.. ) 님의 말 :
MFC클래스레벨에서
심민조 ( [민조] I saw U.. ) 님의 말 :
사용자편의를 위해
심민조 ( [민조] I saw U.. ) 님의 말 :
구분한거라고하네
 

즉 별개의 메시지 창을 가지고 메시지 창을 따로 띄우고 싶으면 UI  쓰레드를,
그냥 백그라운드에서 작업하려면 worker 쓰레드를 쓴다.. 라고 간단히 정리 된다.


여하간 몇시간동안 살펴보다가 코딩을 했고 실제 코딩시간은 한 2시간? 쯤 걸렸다.
코드는 다음과 같다. 복 붙 해도 실행은 안 될 것이다. 대략적인 흐름만 기억해두기 위해
헤더파일과 다른 파일은 붙여넣지 않고
메인 코드만 붙여넣었으니.

조금 허접하다. 느낌이 뭔가 inefficient하다.

#include "stdafx.h"
#include "Resource.h"
#include "MyThread.h"
#include <process.h>
#include <stdlib.h>
#include <windows.h>

#ifdef _DEBUG
#define new DEBUG_NEW
#endif


typedef int buffer_item;
#define BUFFER_SIZE 5

//CWinApp theApp;
using namespace std;

static int in=0;  //0으로 초기화
buffer_item buffer[BUFFER_SIZE];

HANDLE hmutex,psema,csema; //생산 또는 소비 할때 1개 쓰레드만 작업 할 수 있게 하기 위해 mutex로 임계영역을 설정하고, 버퍼 사이즈 만큼
//쓰레드가 생산할 수 있게 하도록 하기 위해 psemaphore를 이용하여 초기값을 BUFFER_SIZE 만큼 할당하였다.
//생산자 쓰레드가 버퍼를 다 채우면, csemaphore를 통해 소비자쓰레드가 버퍼를 소비하도록 하였다.


CWinThread *pThread[50]; //Thread pool. 미리 50개쯤 잡아둔다
CWinThread *cThread[50]; //Thread pool. 미리 50개쯤 잡아둔다
int isWorking=1;

 

int insert_item(buffer_item item) {

 buffer[in]=item;
 in=(in+1)%BUFFER_SIZE;
 return 0;
}


int remove_item(buffer_item *item) {

 if( in !=0 ){ //생산된 상품이 있다면
  *item=buffer[in-1];
  buffer[in-1]=0;
  in--;
 }
 else if ( (in==0) && (buffer[BUFFER_SIZE -1] !=0) ) {  //상품 버퍼가 모두 다 찼다면
  *item=buffer[BUFFER_SIZE-1];
  buffer[BUFFER_SIZE-1]=0; 
  in=BUFFER_SIZE-1;
 }
 return 0;
}


UINT producer(void *pData)
{
 int sleepTime=0;
 buffer_item item;


 while(isWorking==1) {
  //********************************임계영역 설정***********************************
  WaitForSingleObject(psema, INFINITE); 
  WaitForSingleObject(hmutex, INFINITE);

   sleepTime=rand()%3000; //임의의 시간으로 쉬대 최대 3초까지만 쉰다
   Sleep(sleepTime);
   item=rand()+1;
   printf("producer produced %d  \n",item);

   insert_item(item);

  ReleaseMutex(hmutex);
  ReleaseSemaphore(csema,1,NULL);
  //********************************임계영역 설정***********************************
 }
 return 1;

}


UINT consumer(void *pData)
{
 int sleepTime=0;
 buffer_item item=0;


 while(isWorking==1) {
  //********************************임계영역 설정***********************************
  WaitForSingleObject(csema,INFINITE); //버퍼가 다 차면!
  WaitForSingleObject(hmutex, INFINITE);

   sleepTime=rand()%3000; //임의의 시간으로 쉬대 최대 3초까지만 쉰다
   Sleep(sleepTime);

   remove_item(&item);
   printf("consumer consumed %d  \n", item);

  ReleaseMutex(hmutex);
  ReleaseSemaphore(psema,1,NULL);
  //********************************임계영역 설정***********************************
 }

 return 1;
}

 

int _tmain(int argc, TCHAR* argv[], TCHAR* envp[])
{

 hmutex=CreateMutex(NULL, FALSE, NULL);
 psema=CreateSemaphore(NULL,BUFFER_SIZE,BUFFER_SIZE,NULL);
 csema=CreateSemaphore(NULL,0,1,NULL);

 int time=2,numProducer=1,numConsumer=1; //기본값으로 1초실행, 생산자, 소비자 쓰레드 1개씩 할당.

 printf("Please enter the whole work time(second). \n");
 scanf("%d", &time);
 time*=1000;

 printf("Please enter the number of producer thread \n");
 scanf("%d", &numProducer);

 printf("Please enter the number of consumer thread \n");
 scanf("%d", &numConsumer);


 for(int i=0; i<numProducer ; i++)
  pThread[i] = AfxBeginThread(producer,
  THREAD_PRIORITY_NORMAL,
  0, // stack size
  CREATE_SUSPENDED);

 for(int i=0; i<numConsumer ; i++)
  cThread[i] = AfxBeginThread(consumer,
  THREAD_PRIORITY_NORMAL,
  0, // stack size
  CREATE_SUSPENDED);


 Sleep(time);
 isWorking=0;  //작업 시간 종료
 printf("Time is over.... done!! \n");


 return 0;
}

 


'etc..' 카테고리의 다른 글

컴파일시 실행코드 사이즈 줄이는법  (0) 2010.09.27
ESQL 기본개념  (0) 2010.09.24
[MFC]쓰레드 이용법  (0) 2010.05.23
[MFC] multi-thread 사용법 기초  (0) 2010.05.22
[VC++] Run-Time Lib  (0) 2010.05.21