728x90

생산자/소비자 모델

- 입력 출력 모델을 디자인할 때 입력을 담당하는 쓰레드와 출력을 담당하는 쓰레드로 구성을 함

- 입력 쓰레드를 생산자 쓰레드, 출력 쓰레드를 소비자 쓰레드라고 함

- 입력 쓰레드는 받은 데이터를 버퍼에 데이터를 쌓고 출력 쓰레드는 버퍼에서 데이터를 가져가서 출력을 해주게 됨

- 생산자가 먼저 실행이 되고 완료된 후  소비자가 실행이 되어야 함

- 위 순서가 잘못되면 원하는 작동을 하지 않을 수 있음

 

이벤트 기반 동기화

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;
}

    -> 두 쓰레드 모두 실행

728x90

+ Recent posts