생산자/소비자 모델
- 입력 출력 모델을 디자인할 때 입력을 담당하는 쓰레드와 출력을 담당하는 쓰레드로 구성을 함
- 입력 쓰레드를 생산자 쓰레드, 출력 쓰레드를 소비자 쓰레드라고 함
- 입력 쓰레드는 받은 데이터를 버퍼에 데이터를 쌓고 출력 쓰레드는 버퍼에서 데이터를 가져가서 출력을 해주게 됨
- 생산자가 먼저 실행이 되고 완료된 후 소비자가 실행이 되어야 함
- 위 순서가 잘못되면 원하는 작동을 하지 않을 수 있음
이벤트 기반 동기화
HANDLE CreateEventA(
LPSECURITY_ATTRIBUTES lpEventAttributes,
BOOL bManualReset, // 자동 리셋(FALSE), 수동 리셋 설정(TRUE)
BOOL bInitialState, // 이벤트 오브젝트 초기 상태 Non-Signaled(FALSE), Signaled(TRUE)
LPCSTR lpName
);
BOOL SetEvent(
HANDLE hEvent
);
BOOL ResetEvent(
HANDLE hEvent
);
- 생산자 쓰레드가 실행이 완료 됐다고 알려주면 소비자 쓰레드가 실행되도록 함
- 이벤트 오브젝트를 만들고 Non-Signaled 상태로 놓고 생산자 쓰레드가 완료가 되면 Signaled 상태로 바꿔서 완료됐다고 알려주면 소비자 쓰레드가 작업을 함
- 수동 리셋 모드 이벤트
-> 이벤트 오브젝트의 상태를 수동으로 조작하지 않으면 상태가 변하지 않는 이벤트
-> 둘 이상의 쓰레드가 대기중일때 생산자 쓰레드가 이벤트 오브젝트를 Signaled 상태로 바꾸면 ResetEvent를 하지 않는 이상 Signalad 상태가 유지되므로 쓰레드가 모두 실행될 수 있음
- 자동 리셋 모드 이벤트
-> Singaled로 바꾸는 것은 수동이지만 Non-Signaled 상태가 되는 것은 자동
-> 둘 이상의 쓰레드가 대기중일때 생산자 쓰레드가 이벤트 오브젝트를 Signaled 상태로 바꾸면 WaitForSingleObject로 대기하고 있는 쓰레드 중 하나의 쓰레드만 실행을 할 수 있음
- 둘 이상의 쓰레드를 사용할 때 자동 리셋 모드와 수동 리셋 모드
// 자동 리셋 모드
#include <stdio.h>
#include <tchar.h>
#include <windows.h>
#include <process.h>
TCHAR string[100];
HANDLE hEvent;
unsigned int WINAPI OutputThreadFunction(LPVOID lpParam)
{
WaitForSingleObject(hEvent, INFINITE); // 이벤트 상태가 Signaled 상태가 되기를 기다림
_fputts(_T("Output String : "), stdout);
_fputts(string, stdout);
return 0;
}
unsigned int WINAPI CountThreadFunction(LPVOID lpParam)
{
WaitForSingleObject(hEvent, INFINITE); // 이벤트 상태가 Signaled 상태가 되기를 기다림
_tprintf(_T("Output String length : %d \n"), (_tcslen(string) - 1));
return 0;
}
int _tmain(int argc, TCHAR* argv[])
{
HANDLE hThread[2];
DWORD dwThreadID[2];
hEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
if (hEvent == NULL)
{
_fputts(_T("Event object createion error\n"), stdout);
return -1;
}
hThread[0] = (HANDLE)_beginthreadex(NULL, 0, OutputThreadFunction, NULL, 0, (unsigned*)& dwThreadID[0]);
hThread[1] = (HANDLE)_beginthreadex(NULL, 0, CountThreadFunction, NULL, 0, (unsigned*)& dwThreadID[1]);
if (hThread[0] == NULL || hThread[1] == NULL)
{
_fputts(_T("thread createion error\n"), stdout);
return -1;
}
_fputts(_T("Insert String : "), stdout);
_fgetts(string, 30, stdin);
SetEvent(hEvent); // 이벤트 오브젝트 상태를 Signaled 상태로 변경
WaitForMultipleObjects(2, hThread, TRUE, INFINITE);
CloseHandle(hEvent);
CloseHandle(hThread[0]);
CloseHandle(hThread[1]);
return 0;
}
-> 두개의 쓰레드 중 하나의 쓰레드만 실행이 됨
// 수동 모드 리셋
#include <stdio.h>
#include <tchar.h>
#include <windows.h>
#include <process.h>
TCHAR string[100];
HANDLE hEvent;
unsigned int WINAPI OutputThreadFunction(LPVOID lpParam)
{
WaitForSingleObject(hEvent, INFINITE); // 이벤트 상태가 Signaled 상태가 되기를 기다림
_fputts(_T("Output String : "), stdout);
_fputts(string, stdout);
return 0;
}
unsigned int WINAPI CountThreadFunction(LPVOID lpParam)
{
WaitForSingleObject(hEvent, INFINITE); // 이벤트 상태가 Signaled 상태가 되기를 기다림
_tprintf(_T("Output String length : %d \n"), (_tcslen(string) - 1));
return 0;
}
int _tmain(int argc, TCHAR* argv[])
{
HANDLE hThread[2];
DWORD dwThreadID[2];
hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
if (hEvent == NULL)
{
_fputts(_T("Event object createion error\n"), stdout);
return -1;
}
hThread[0] = (HANDLE)_beginthreadex(NULL, 0, OutputThreadFunction, NULL, 0, (unsigned*)& dwThreadID[0]);
hThread[1] = (HANDLE)_beginthreadex(NULL, 0, CountThreadFunction, NULL, 0, (unsigned*)& dwThreadID[1]);
if (hThread[0] == NULL || hThread[1] == NULL)
{
_fputts(_T("thread createion error\n"), stdout);
return -1;
}
_fputts(_T("Insert String : "), stdout);
_fgetts(string, 30, stdin);
SetEvent(hEvent); // 이벤트 오브젝트 상태를 Signaled 상태로 변경
WaitForMultipleObjects(2, hThread, TRUE, INFINITE);
CloseHandle(hEvent);
CloseHandle(hThread[0]);
CloseHandle(hThread[1]);
return 0;
}
-> 두 쓰레드 모두 실행
'Programming > System Programming' 카테고리의 다른 글
윈도우즈 시스템 프로그래밍 - 14. 쓰레드 동기화 기법2(3) (0) | 2020.08.09 |
---|---|
윈도우즈 시스템 프로그래밍 - 14. 쓰레드 동기화 기법2(2) (0) | 2020.08.09 |
윈도우즈 시스템 프로그래밍 - 13. 쓰레드 동기화 기법1(4) (0) | 2020.08.05 |
윈도우즈 시스템 프로그래밍 - 13. 쓰레드 동기화 기법1(3) (0) | 2020.08.04 |
윈도우즈 시스템 프로그래밍 - 13. 쓰레드 동기화 기법1(2) (0) | 2020.08.03 |