`

多线程中的事件对象

 
阅读更多
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;
    }
}
分享到:
评论

相关推荐

    多线程事件对象通讯

    总之,多线程事件对象通讯是Windows编程中的重要概念,通过理解和掌握这一技术,开发者可以编写出更加高效和可靠的多线程程序。在这个例子中,`vc技术内幕11章`为我们提供了一个实用的实践平台,帮助我们深入理解...

    MFC多线程 多事件

    本文将深入探讨如何利用MFC来实现多线程以及多事件之间的相互触发。 首先,多线程是并发编程的一种方式,允许程序同时执行多个独立的任务。在MFC中,我们可以使用`CWinThread`类来创建和管理线程。创建一个新的线程...

    事件内核对象详解(多线程编程)

    事件内核对象是多线程编程中的一种重要的通信机制。它是一种抽象的对象,有两种状态:未受信(nonsignaled)和受信(signaled)。编程人员可以使用WaitForSingleObject函数等待其变成受信状态。事件对象包含三个成员...

    vc 多线程编程之事件

    在提供的"EventTest"示例中,可能包含了如何创建事件对象、设置和重置事件,以及在多线程中使用事件进行同步的具体代码实现,这有助于理解和掌握事件在实际项目中的应用。读者可以通过分析这个示例,更深入地了解...

    vc++ multithread多线程教程---线程通信--利用事件对象,线程同步--使用信号量,线程同步--使用互斥量,线程同步--使用临界区

    本教程将深入探讨四种常见的线程同步机制:事件对象、信号量、互斥量以及临界区,帮助开发者理解和掌握如何在VC++中安全地实现多线程通信。 一、事件对象 事件对象是Windows API中用于线程间通信的一种同步机制。它...

    MFC两个线程中用事件内核对象通信

    在Windows编程中,多线程应用常常需要进行线程间通信来协调工作。MFC(Microsoft Foundation Classes)作为C++的库,提供了丰富的类和函数支持这种通信。本实例是基于VS2013开发环境,针对Win10 64位系统,展示了...

    C++面向对象多线程编程

    《C++面向对象多线程编程》共分13章,全面讲解构建多线程架构与增量多线程编程...第11章讨论C++对象在多线程环境中的行为和交互方式。第12章简单介绍多线程应用程序的测试技术。第13章对全书内容进行扼要地回顾与思考。

    [Delphi]多线程编程(13)多线程同步之Event(事件对象).pdf

    标题《[Delphi]多线程编程(13)多线程同步之Event(事件对象)》意味着这份文档关注于Delphi编程语言中处理多线程时如何使用事件对象进行线程间的同步。在多线程编程中,事件(Event)是一种同步机制,用于控制线程的...

    易语言利用Event事件实现多线程暂停继续源码

    在IT行业中,多线程编程是一项重要的技术,它允许程序同时执行多个任务,提高系统效率。易语言作为一款中国本土的编程语言,以其简洁的语法和面向对象的设计思想,为开发者提供了实现多线程功能的可能。本篇将详细...

    学习多线程之一:线程通信--利用事件对象.zip_线程通信

    了解了基本概念后,深入学习"Thread1"代码将帮助你更好地理解事件对象在实际多线程环境中的应用。通过分析代码,你可以看到如何创建事件对象,如何在适当的时候设置和清除事件,以及如何使用wait()和notify()(或其...

    面向对象的多线程编程

    - **线程对象**:`std::thread`是C++标准库中用于创建和管理线程的核心类。它提供了创建新线程、等待线程完成等基本操作的方法。 - **线程函数**:每个线程都需要一个函数作为入口点,该函数通常称为线程函数或线程...

    当析构函数遇到多线程── C++ 中线程安全的对象回调 PDF

    ### 当析构函数遇到多线程——C++中线程安全的对象回调 #### 1. 多线程下的对象生命期管理 C++作为一种需要程序员手动管理对象生命周期的语言,在多线程环境中尤其需要谨慎处理对象的创建和销毁过程。由于多线程...

    武汉理工大学 面向对象与多线程综合实验 档案管理系统

    【武汉理工大学】的这个【面向对象与多线程综合实验】是一个典型的软件开发项目,旨在让学生深入理解并实践这两种核心技术在实际系统中的应用。在这个实验中,学生将设计并实现一个【档案管理系统】,该系统服务于三...

    用VB6实现多线程

    在VB6(Visual Basic 6)环境中,多线程是一个重要的技术,它允许程序同时执行多个任务,提高程序的响应性和效率。VB6本身并不直接支持多线程,但可以通过调用Windows API来实现。本篇文章将深入探讨如何在VB6中实现...

    秒杀windows多线程之事件

    通过学习本篇文档,读者将掌握如何在Windows平台上使用事件对象来实现线程间的同步和互斥,以及如何在多线程编程中应用这些概念来解决实际问题。这些知识点对于希望深入学习Windows多线程编程的开发者来说是非常宝贵...

    java多线程的条件对象和锁对象demo

    在Java编程语言中,多线程是并发执行多个任务的关键技术。这允许程序在等待某个操作完成时继续处理其他任务,从而提高了系统资源的利用率和程序的响应速度。本示例"java多线程的条件对象和锁对象demo"着重探讨了如何...

    c++ 面向对象多线程编程

    在C++编程中,面向对象和多线程是两个重要的概念,它们对于开发高效、并发的软件至关重要。本文将深入探讨这两个主题,并结合C++语言特性进行详细解释。 首先,让我们了解一下面向对象编程(Object-Oriented ...

Global site tag (gtag.js) - Google Analytics