イベント オブジェクトの使用 (同期)
アプリケーションでは、さまざまな状況で イベント オブジェクト を使用して、待機中のスレッドにイベントの発生を通知できます。 たとえば、ファイル、名前付きパイプ、通信デバイスに対する重複した I/O 操作では、イベント オブジェクトを使用して完了を通知します。 重複した I/O 操作でのイベント オブジェクトの使用の詳細については、「 同期と重複入力と出力」を参照してください。
次の例では、イベント オブジェクトを使用して、マスター スレッドがそのバッファーへの書き込みを行っている間に、複数のスレッドが共有メモリ バッファーから読み取るのを防ぎます。 最初に、マスター スレッドは CreateEvent 関数を使用して、初期状態が非署名の手動リセット イベント オブジェクトを作成します。 次に、複数のリーダー スレッドを作成します。 マスター スレッドは書き込み操作を実行し、書き込みが完了したときにイベント オブジェクトをシグナル状態に設定します。
読み取り操作を開始する前に、各リーダー スレッドは 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;
}