返回首页

介绍
的C / C程序可以使用Win32事件对象,在若干情况下,通知等待线程的事件发生。例如,文件,命名管道和通信的重叠I / O操作的设备使用一个事件对象信号完成。Win32事件
Win32事件就像一个状态机的工作和花费之间的两个国家,即它的生命,这标志着国家和无信号状态。信号状态是指一个事件,它有能力释放线程等待该事件发出信号。事件是指在无信号状态,它不会释放任何线程正在等待这一特定事件。事件有两种类型:手动重置事件和自动重置事件。手动事件有一个信号的用户设置为无信号状态,手动使用ResetEvent函数。自动自动重置事件发生对象时提出的无信号状态。
CreateEvent函数用于创建事件的线程同步对象。手动或自动重置事件选择中提到CreateEvent函数的参数初始化。等待家庭功能(WaitForSingleObject的,WaitForMultipleObjects的)用来等待一个特定的事件发生时。组对象等待事件:单个对象的信号,或者在整个事件中的线程发出信号。此功能可以创建命名和未命名的事件对象。 SetEvent的功能是用来设置事件对象的信号状态。 ResetEvent函数用于设置事件对象的非信号状态。如果函数成功,返回该事件的句柄。如果命名的事件已经是可用的,GetLastError函数返回ERROR_ALREADY_EXISTS标志。如果命名的事件已经是可用的,OpenEvent函数用于访问先前由CreateEvent函数创建事件。代码说明
下面的示例使用事件对象来演示如何子线程的信号事件告知其主线程完成。多个线程等待主线程,这是确保进一步执行之前完成所有的线程。

//    Create an Manual Reset Event where events must be reset 

//    manually to non signaled state

HANDLE     hEvent1 = CreateEvent ( NULL , true , false , L"MyEvent1" );

if ( !hEvent1 ) return -1;





HANDLE     hEvent2 = CreateEvent ( NULL , true , false , L"MyEvent2" );

if ( !hEvent2 ) return -1;





HANDLE     hEvent3 = CreateEvent ( NULL , true , false , L"MyEvent3" );

if ( !hEvent3 ) return -1

我们创建三个事件MyEvent1,MyEvent2,MyEvent3分别。使用CreateEvent(NULL,则真,假quot; MyEventquot的;);创建一个事件。参数说明如下:第一个参数为NULL代表默认的安全属性。第二个参数是一个手动复位事件的标志。虚假意味着事件将自动重置事件,手动重置事件标志,如果是真实的。第三个参数是一个正在创建事件的状态标志。如果为false,将创建活动,在无信号状态,如果属实,该事件将被创建的信号状态。信号状态创建一个事件意味着,将没有任何调用SetEvent的(...)发布的第一个线程正在等待信号;自动重置事件的情况下。在手动复位事件的情况下,所有的线程将被释放,正在等待这个信号,除非有调用ResetEvent(...)。第四个参数是与它全球将确定事件的名称。如果上述事件具有相同的名称已经存在,那么现有的事件句柄将被打开。{C}
三个独立的线程都推出了各自的方法。这些线程函​​数将模拟睡在他们的执行时间为5,10,15秒​​,他们的任务。事件句柄保存在一个数组,所以Array_Of_Events_Handles主线程可以等待这些句柄。
DWORD WINAPI ThreadFun1( LPVOID n )

{

    cout<<"Thread Instantiated 1........."<<endl;



    // Get the handler to the event for which we need to wait in 



    //    this thread.

    HANDLE hEvent = OpenEvent ( EVENT_ALL_ACCESS , false, L"MyEvent1" );

    if ( !hEvent ) { return -1; }



    Sleep ( 5000 );



    ResetEvent ( hEvent );

    // Signal the event

    if (SetEvent ( hEvent ))

    {

        cout<<"Got The signal - MyEvent 1......."<<endl;

    }    



    CloseHandle ( hEvent );

    cout<<"End of the Thread 1......"<<endl;

    return 0;

}

以上是一个线程函数的例子。这基本上打开已经创建的事件,并将其重置手动5秒钟后睡觉。
现在,因为我们所有的三个线程等待处理,直到它标志着'ResetEvent(的hEvent)',线程同步,主线程等待其完成之前提前执行。输出是控制台日志给你一个事件序列的感觉。
{S0的}兴趣点
"WaitForMultipleObjects的"有限等待上MAXIMUM_WAIT_OBJECTS的处理计数,这是64。如果我们需要等待比MAXIMUM_WAIT_OBJECTS处理的,我们可以创建一个单独的线程等待MAXIMUM_WAIT_OBJECTS的和然后等待这些线程完成。使用这种方法,我们可以创建MAXIMUM_WAIT_OBJECTS线程,这些每个人都可以等待MAXIMUM_WAIT_OBJECTS对象处理。 {A}。创建多线程中的一些实际情况,似乎没有无风险,有可能是一个线程同步开销。尤其是当你有太多数量的处理等,所有句柄都被认为是信号前等待线程可以继续进一步。我写我自己的分机的WaitForAllObjects解决了这个超过64把手都应该发出信号,即等待的情况下非常有用,"bWaitAll = TRUE'。{体C3}
上面的代码基本上是在一个循环的第64 WaitForMultipleObjects的处理在一个数组"把手"。事件/处理信号时,他们从'把手'阵列和阵列推余下的句柄。这种情况持续下去,直到所有的手柄正在等待他们的信号。历史11年3月11日:首次发布。11年4月11日:第一次更新 - 意见的基础上,纠正了数组来保存事件句柄。

回答

评论会员:游客 时间:2012/02/06
Mitendra阿南德:删除所有相关的事件的代码,并运行它,你会看到完全相同的行为。你做了不同步的基础上发生的事件。威廉・E・肯普夫
Mitendra阿南德:{S}代码中有错字。
- 主线程正在等待的线程的句柄数组。因此,只等待线程终止,不论事件信号。
- 我已经改变了数组来保存事件句柄现在你可以测试和验证,它的作品
- 我还增加了对WaitForMultipleObjects的"使代码更清晰一些返回检查

感谢我的文章评论
评论会员:Mitendra阿南德 时间:2012/02/06
。两个问题保持这种变化

1。这是毫无意义的,由ResetEvent SetEvent的紧随其后。事实上,这样做可能会导致一场比赛的条件。

2。示例代码说明如何使用事件,但不为什么,因为你可能只是在等待的线程处理(如你本来)。不幸的是,更复杂的例子有可能导致竞争条件,正如我在其他线程。
威廉・E・肯普夫
评论会员:Mitendra阿南德 时间:2012/02/06
我只是看到,在更新后的代码,你改变了订货SetEvent的后面是ResetEvent。在这个很窄的例子,这已删除任何机会的比赛条件(我认为),但它仍然是毫无意义的。你不需要调用ResetEvent所有。
威廉・E・肯普夫
评论会员:Mitendra阿南德 时间:2012/02/06
是,在这有限的情况下。我还是愿意显示自动和手动复位事件的作品,并没有提到如何在不同情况下使用的API的优点和利弊。

此外,你不会想在线程中使用ResetEvent()时要释放多个线程在等待该事件。在这种情况下,你应该等待被重置事件之前公布的所有线程,但你所需要的指示或信号之前再次重置事件,这又增加了一层复杂性。这将是很有帮助是否杀死所有的线程等待该事件的
评论会员:。pwasser 时间:2012/02/06
我觉得那里是语言障碍在这里,但"你会不喜欢ResetEvent()在线程当你想释放多个线程在等待该事件"不会有任何意义我。
威廉・E・肯普夫
评论会员:pwasser 时间:2012/02/06
现在,我再次读取该行,即使我发现它神秘的{S}

我的意思是:
是一个案例时ResetEvent()变得复杂。也就是说,当有等待同一事件的多张线程。理想的情况下,这些等待线程得到释放之前,ResetEvent()。但这里又复杂性会以某种方式表明等待线程释放做ResetEvent()
评论会员:游客 时间:2012/02/06
pwasser:我很困惑的是,为什么你认为你需要ResetEvent?在任何情况下,当事件成为信号,所有等待的线程被唤醒,所以不存在你所描述的问题。真正的问题是,如果一个线程尚未WaitForMultipleObjects的调用,而只是指出,但另一场比赛中的许多事件的误导用途条件inherant。再次,坚持条件变量。威廉・E・肯普夫
Mitendra阿南德:"确定"。两件事情: -
1。我们需要ResetEvent(),以便获得该事件的信号状态。因此,该事件可以为不同目的而再次使用后,如果需要。自动复位不会有这个问题,我同意。但是,手动复位都有它自己的目的。
2。如果线程没有被称为"WaitForMultipleObjects的()',但事件已经暗示了。再后来,这个信号时,捡起线程调用WaitForMultipleObjects的()。但是当你解释比赛条件是可能的,如果不仔细编码,我同意
评论会员:游客 时间:2012/02/06
pwasser:您的使用不重用的事件,并调用ResetEvent是毫无意义的。你说在文章中的一些假设,而不是代码的代码吗?威廉・E・肯普夫:胡马云・卡比尔马蒙:是的,我说的一些假设,而不是在文章中的代码的代码。和我同意,调用ResetEvent在我的文章没有任何这样的目的。毕竟这只是一个虚拟的代码。可能我会更新文章显示ResetEvent使用,当我到达的时间:Mitendra阿南德:正如我们所知道假设的代码总是完美的作品||彼得・瓦瑟
pwasser:他们是非常困难的,在大多数情况下使用,不会造成竞争条件。



条件变量或显示器应该使用。
威廉・E・肯普夫
评论会员:游客 时间:2012/02/06
Mitendra阿南德:这是一个相当有充分证据,以支持它的主观声明。使用事件的原因之一是速度。互斥是慢得多。'1111月3彼得・瓦瑟修改
pwasser:对不起,没有,还有大量的证据来支持它,和我提供的这种提法至少有两个。事件做任何保护共享状态。如果您的使用涉及任何共享状态,你不能只使用事件。结合同步的概念,如互斥或关键部分的事件是非常难做到不引入竞争条件。 Win32的现在,有一个条件变量。NET中一直有监视器和C标准,先后引进了条件变量以及。大多数情况下,有人使用的事件,他们应该使用这些替代品之一。
威廉・E・肯普夫