본문 바로가기
Programming/System Programming

[WIN32 / C] CreateEvent를 이용한 투표 프로그래밍!!(Thread순서동기화)

by Winduck 2017. 4. 1.
반응형

최근에 프로그래밍책을 통하여 순서동기화에 대해 공부하였습니다.

순서동기화는 멀티쓰레드환경에서 실행이 순서대로 실행되도록 합니다.

예를들어 투표장소에 들어갈 수 있는 인원이 1인데 투표자가 들어가 투표하는 동안 다른 기다리는 인원은 앞선사람이 투표를 끝낸이후 투표장소가 비워졌을 때 투표를 할 수 있습니다.이것을 이용하여 투표프로그램을 만들었습니다.

프로그램에 대해 간단히 설명하자면 투표공간 2군대를 만들고 10명의 사람이 투표를 하는 프로그램입니다.

핵심은!!! 투표공간 한군데에 1명만 들어가야한다는 것!에 중점을 두고 진행하였습니다.


#include<stdio.h>
#include<tchar.h>
#include<Windows.h>
#include<process.h>
#include<conio.h>
#include<locale.h>

//투표자수 10명
#define voter_num 10
//투표장소 숫자
#define vote_area 2
//투표함수
unsigned int WINAPI voter(LPVOID lpParam);

//투표장소 선언
HANDLE hvote[vote_area] = { "", };

int _tmain(int argc, TCHAR *argv[])
{
 HANDLE hThread[voter_num];

 //한글을 사용하기위함
 setlocale(LC_ALL, "");

 //투표장소 할당
 for (int i = 0; i < vote_area; i++)
 {
  hvote[i] = CreateEvent(
   NULL, // 상속 불가
   TRUE, // auto-reset off
   FALSE,// non-signaled
   NULL //이름없는 event
  );
  if (hvote[i] == NULL)
  {
   _tprintf(_T("Create Event %d fail : %d"), i, GetLastError());
   return -1;
  }
 }

 //투표자 생성
 for (int i = 0; i < voter_num; i++)
 {
  hThread[i] = (HANDLE)_beginthreadex(NULL, 0,
   voter, (LPVOID)i,
   0, NULL);
  if (hThread[i] == NULL)
  {
   _tprintf(_T("_beginthreadex %d fail : %d"), i, GetLastError());
   return -1;
  }
 }
 //투표시작
 for (int i = 0; i < vote_area; i++)
 {
 SetEvent(hvote[i]);
 }
 _fputts(_T("투표가 시작되었습니다.\n"), stdout);

 

 //모든사람이 투표가 끝날때까지 대기
 WaitForMultipleObjects(voter_num,
  hThread,
  TRUE, //모든 Thread가 종료될때 리턴
  INFINITE// signaled상태까지 무한정 대기

 );

 _fputts(_T("투표가 종료되었습니다.\n"), stdout);


 for (int i=0; i < voter_num; i++)
 {
  CloseHandle(hThread[i]);
  CloseHandle(hvote[i]);
 }
 return 0;
}


///투표하기 함수
unsigned int WINAPI voter(LPVOID lpParam)
{
 WaitForMultipleObjects(
  vote_area,
  hvote,
  FALSE, // 투표장소중 한 곳이라도 빈 경우 리턴
  INFINITE // signaled상태까지 무한정 대기
 );
 _tprintf(_T("투표자번호 %d가 투표를 완료하였습니다\n"), (int)lpParam +1);
 return 0;



위 코드에서 빨간색은 주목해야 할 부분이다. 사용된 API를 간단히 살펴보자.

HANDLE WINAPI CreateEvent(
  _In_opt_ LPSECURITY_ATTRIBUTES lpEventAttributes,
  _In_     BOOL                  bManualReset,
  _In_     BOOL                  bInitialState,
  _In_opt_ LPCTSTR               lpName
);

- lpEventAttributes : 보안속성구조체이다. 하위프로세스에게 핸들값을 상속가능여부를 결정.

- bManualReset : 자동 RESET을 ON/OFF시킨다. 이를 설정함으로 WaitForSingObjects나 WaitForMultipleObjects가 리턴될 경우 Event가 자동으로

                        non-signaled가 될지를 결정(True : OFF , FALSE : ON)

- bInitialState : 초기값상태를 signaled/non-signaled상태 결정 (TRUE : signaled , FALSE : non-signaled)

- lpName : Event이름(NULL의 경우 이름 없는 Event)


* RETURN : 반환값

-이벤트의 핸들값을 반환한다.


 DWORD WINAPI WaitForMultipleObjects(
  _In_       DWORD  nCount,
  _In_ const HANDLE *lpHandles,
  _In_       BOOL   bWaitAll,
  _In_       DWORD  dwMilliseconds
);

- nCount : 관찰할 커널오브젝트 숫자

- lpHandles : 커널오브젝트 핸들배열정보포함

- bWaitAll : 모든 커널 오브젝트가 signaled상태가 되기까지 대기( TRUE : 모든 커널오브젝트 ,FALSE : 관찰오브젝트중 하나)

- dwMilliseconds : 대기할 시간을 결정


* RETURN : 반환값

- WaitForMultipleObjects가 리턴된 이유를 설명


위코드에는 없지만 WaitForSingleObject를 잠깐 설명한다.

 DWORD WINAPI WaitForSingleObject(
  _In_ HANDLE hHandle,
  _In_ DWORD  dwMilliseconds
);

-hHandle : 관찰할 커널 오브젝트 핸들

-dwMilliseconds : 대기할 시간 결정


* RETURN : 반환값

- WaitForMultipleObjects가 리턴된 이유를 설명

한가지 커널오브젝트만을 관찰하기때문에 심플하다.


※실행결과


 


순서동기화에 초점을 맞추다보니 별도의 후보자등은 설정하지 않았습니당~ 나중에 후보 랜덤값을 이용해서 후보자(호랭이,사자등)등록해서 하면
더 재미있을거같네요. 이상입니당~~




반응형

댓글