이벤트 개체 사용(동기화)
애플리케이션은 여러 상황에서 이벤트 개체 를 사용하여 대기 스레드에 이벤트 발생을 알릴 수 있습니다. 예를 들어 파일, 명명된 파이프 및 통신 디바이스에서 겹치는 I/O 작업은 이벤트 개체를 사용하여 완료 신호를 보냅니다. 겹치는 I/O 작업에서 이벤트 개체를 사용하는 방법에 대한 자세한 내용은 동기화 및 겹치는 입력 및 출력을 참조하세요.
다음 예제에서는 이벤트 개체를 사용하여 master 스레드가 해당 버퍼에 쓰는 동안 여러 스레드가 공유 메모리 버퍼에서 읽지 못하도록 합니다. 먼저 master 스레드는 CreateEvent 함수를 사용하여 초기 상태가 서명되지 않은 수동 재설정 이벤트 개체를 만듭니다. 그런 다음 여러 판독기 스레드를 만듭니다. master 스레드는 쓰기 작업을 수행한 다음, 쓰기가 완료되면 이벤트 개체를 신호 상태로 설정합니다.
읽기 작업을 시작하기 전에 각 판독기 스레드는 WaitForSingleObject를 사용하여 수동 재설정 이벤트 개체가 신호를 받을 때까지 기다립니다. WaitForSingleObject가 반환되면 기본 스레드가 읽기 작업을 시작할 준비가 되었음을 나타냅니다.
#include <windows.h>
#include <stdio.h>
#define THREADCOUNT 4
HANDLE ghWriteEvent;
HANDLE ghThreads[THREADCOUNT];
DWORD WINAPI ThreadProc(LPVOID);
void CreateEventsAndThreads(void)
{
int i;
DWORD dwThreadID;
// Create a manual-reset event object. The write thread sets this
// object to the signaled state when it finishes writing to a
// shared buffer.
ghWriteEvent = CreateEvent(
NULL, // default security attributes
TRUE, // manual-reset event
FALSE, // initial state is nonsignaled
TEXT("WriteEvent") // object name
);
if (ghWriteEvent == NULL)
{
printf("CreateEvent failed (%d)\n", GetLastError());
return;
}
// Create multiple threads to read from the buffer.
for(i = 0; i < THREADCOUNT; i++)
{
// TODO: More complex scenarios may require use of a parameter
// to the thread procedure, such as an event per thread to
// be used for synchronization.
ghThreads[i] = CreateThread(
NULL, // default security
0, // default stack size
ThreadProc, // name of the thread function
NULL, // no thread parameters
0, // default startup flags
&dwThreadID);
if (ghThreads[i] == NULL)
{
printf("CreateThread failed (%d)\n", GetLastError());
return;
}
}
}
void WriteToBuffer(VOID)
{
// TODO: Write to the shared buffer.
printf("Main thread writing to the shared buffer...\n");
// Set ghWriteEvent to signaled
if (! SetEvent(ghWriteEvent) )
{
printf("SetEvent failed (%d)\n", GetLastError());
return;
}
}
void CloseEvents()
{
// Close all event handles (currently, only one global handle).
CloseHandle(ghWriteEvent);
}
int main( void )
{
DWORD dwWaitResult;
// TODO: Create the shared buffer
// Create events and THREADCOUNT threads to read from the buffer
CreateEventsAndThreads();
// At this point, the reader threads have started and are most
// likely waiting for the global event to be signaled. However,
// it is safe to write to the buffer because the event is a
// manual-reset event.
WriteToBuffer();
printf("Main thread waiting for threads to exit...\n");
// The handle for each thread is signaled when the thread is
// terminated.
dwWaitResult = WaitForMultipleObjects(
THREADCOUNT, // number of handles in array
ghThreads, // array of thread handles
TRUE, // wait until all are signaled
INFINITE);
switch (dwWaitResult)
{
// All thread objects were signaled
case WAIT_OBJECT_0:
printf("All threads ended, cleaning up for application exit...\n");
break;
// An error occurred
default:
printf("WaitForMultipleObjects failed (%d)\n", GetLastError());
return 1;
}
// Close the events to clean up
CloseEvents();
return 0;
}
DWORD WINAPI ThreadProc(LPVOID lpParam)
{
// lpParam not used in this example.
UNREFERENCED_PARAMETER(lpParam);
DWORD dwWaitResult;
printf("Thread %d waiting for write event...\n", GetCurrentThreadId());
dwWaitResult = WaitForSingleObject(
ghWriteEvent, // event handle
INFINITE); // indefinite wait
switch (dwWaitResult)
{
// Event object was signaled
case WAIT_OBJECT_0:
//
// TODO: Read from the shared buffer
//
printf("Thread %d reading from buffer\n",
GetCurrentThreadId());
break;
// An error occurred
default:
printf("Wait error (%d)\n", GetLastError());
return 0;
}
// Now that we are done reading the buffer, we could use another
// event to signal that this thread is no longer reading. This
// example simply uses the thread handle for synchronization (the
// handle is signaled when the thread terminates.)
printf("Thread %d exiting\n", GetCurrentThreadId());
return 1;
}