`

多线程中的事件对象

 
阅读更多
Using Event Objects
使用事件对象
Applications use event objects in a number of situations to notify a waiting thread of the occurrence of an event. For example, overlapped I/O operations on files, named pipes, and communications devices use an event object to signal their completion. For more information about the use of event objects in overlapped I/O operations, see Synchronization and Overlapped Input and Output.
应用程序使用事件对象来通知等待线程事件的发生,常用语IO操作中。

In the following example, an application uses event objects to prevent several threads from reading from a shared memory buffer while a master thread is writing to that buffer. First, the master thread uses the CreateEvent function to create a manual-reset event object. The master thread sets the event object to nonsignaled when it is writing to the buffer and then resets the object to signaled when it has finished writing. Then it creates several reader threads and an auto-reset event object for each thread. Each reader thread sets its event object to signaled when it is not reading from the buffer.

//宏定义
#define NUMTHREADS 4

HANDLE hGlobalWriteEvent;
HANDLE hReadEvents[NUMTHREADS];
//创建事件和线程
void CreateEventsAndThreads(void)
{
    HANDLE hThread;
    DWORD i, IDThread;
//创建人工重置的事件对象,当主线程在写的时候设置为非信号状态。
    // Create a manual-reset event object. The master thread sets
    // this to nonsignaled when it writes to the shared buffer.
//写事件对象
    hGlobalWriteEvent = CreateEvent(
        NULL,         // default security attributes
        TRUE,         // manual-reset event
        TRUE,         // initial state is signaled
        "WriteEvent"  // object name
        );
//判断创建是否成功,不成功就直接返回
    if (hGlobalWriteEvent == NULL)
    {
        printf("CreateEvent failed (%d)\n", GetLastError());
        return;
    }
//创建多线程和每一个线程的自动设置事件对象。当每一个线程不在读的时候设置它为信号状态
    // Create multiple threads and an auto-reset event object
    // for each thread. Each thread sets its event object to
    // signaled when it is not reading from the shared buffer.
//创建多线程的事件对象
    for(i = 0; i < NUMTHREADS; i++)
    {
        // Create the auto-reset event.
        hReadEvents[i] = CreateEvent(
            NULL,     // no security attributes
            FALSE,    // auto-reset event
            TRUE,     // initial state is signaled
            NULL);    // object not named

        if (hReadEvents[i] == NULL)
        {
            printf("CreateEvent failed (%d)\n", GetLastError());
            return;
        }
//创建多线程
        hThread = CreateThread(NULL, 0,
            (LPTHREAD_START_ROUTINE) ThreadFunction,
            &hReadEvents[i],  // pass event handle
            0, &IDThread);
        if (hThread == NULL)
        {
            printf("CreateThread failed (%d)\n", GetLastError());
            return;
        }
    }
}

Before the master thread writes to the shared buffer, it uses the ResetEvent function to set the state of hGlobalWriteEvent (an application-defined global variable) to nonsignaled. This blocks the reader threads from starting a read operation. The master then uses the WaitForMultipleObjects function to wait for all reader threads to finish any current read operations. When WaitForMultipleObjects returns, the master thread can safely write to the buffer. After it has finished, it sets hGlobalWriteEvent and all the reader-thread events to signaled, enabling the reader threads to resume their read operations.
//写的函数

VOID WriteToBuffer(VOID)
{
    DWORD dwWaitResult, i;

    // Reset hGlobalWriteEvent to nonsignaled, to block readers.
//设置写线程事件对象为非信号状态,阻止其他的线程读取数据
    if (! ResetEvent(hGlobalWriteEvent) )
    {
        printf("ResetEvent failed (%d)\n", GetLastError());
        return;
    }
//
    // Wait for all reading threads to finish reading.
//等待所有的读线程完成,返回一个某是信号状态的读线程的索引
    dwWaitResult = WaitForMultipleObjects(
        NUMTHREADS,   // number of handles in array
        hReadEvents,  // array of read-event handles
        TRUE,         // wait until all are signaled
        INFINITE);    // indefinite wait
//判读是否所有的读线程都是信号状态(即所有的读操作都结束了,可以写操作了)
    switch (dwWaitResult)
    {
        // All read-event objects were signaled.
        case WAIT_OBJECT_0:
            // Write to the shared buffer.
            break;

        // An error occurred.
        default:
            printf("Wait error: %d\n", GetLastError());
            ExitProcess(0);
    }
//写完后设置写事件为信号状态,通知其他的读线程可以读操作了
    // Set hGlobalWriteEvent to signaled.
//设置写事件信号状态不成功就返回
    if (! SetEvent(hGlobalWriteEvent) )
    {
        printf("SetEvent failed (%d)\n", GetLastError());
        return;
    }
//设置所有的读进程为信号状态,即初始化所有的读操作事件信号状态,防止读操作之前发生其他错误。
    // Set all read events to signaled.
    for(i = 0; i < NUMTHREADS; i++)
        if (! SetEvent(hReadEvents[i]) )
        {
            printf("SetEvent failed (%d)\n", GetLastError());
            return;
        }
}

Before starting a read operation, each reader thread uses WaitForMultipleObjects to wait for the application-defined global variable hGlobalWriteEvent and its own read event to be signaled. When WaitForMultipleObjects returns, the reader thread's auto-reset event has been reset to nonsignaled. This blocks the master thread from writing to the buffer until the reader thread uses the SetEvent function to set the event's state back to signaled.

//线程主函数
VOID ThreadFunction(LPVOID lpParam)
{
//等待结果字段
    DWORD dwWaitResult;
//两个事件对象
    HANDLE hEvents[2];
//
    hEvents[0] = *(HANDLE*)lpParam;  // thread's read event
    hEvents[1] = hGlobalWriteEvent;
//等待多线程
    dwWaitResult = WaitForMultipleObjects(
        2,            // number of handles in array
        hEvents,      // array of event handles
        TRUE,         // wait till all are signaled
        INFINITE);    // indefinite wait

    switch (dwWaitResult)
    {
        // Both event objects were signaled.
        case WAIT_OBJECT_0:
            // Read from the shared buffer.
            break;

        // An error occurred.
        default:
            printf("Wait error: %d\n", GetLastError());
            ExitThread(0);
    }

    // Set the read event to signaled.

    if (! SetEvent(hEvents[0]) )
    {
        printf("SetEvent failed (%d)\n", GetLastError());
        return;
    }
}
分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics