在 C++ 中创建/打开事件并检查它们是不是被触发
Posted
技术标签:
【中文标题】在 C++ 中创建/打开事件并检查它们是不是被触发【英文标题】:Creating/Opening Events in C++ and checking if they are fired在 C++ 中创建/打开事件并检查它们是否被触发 【发布时间】:2009-03-01 18:23:26 【问题描述】:我有两个线程使用事件进行同步。 在每个线程中,他们使用相同的调用:
::CreateEvent( NULL,TRUE,FALSE,tcEventName )
生产者线程首先进行调用,而消费者线程最后进行调用,所以它在技术上是开放的,而不是创建事件......我假设。
但是,当在生产者线程中调用 SetEvent 时,在消费者线程中永远不会触发相同的事件(我使用的是 WaitForMultipleObjects())
是否有工具可以告诉我事件是否真的被正确触发了。
另外,当我在每个线程中调用 CreateEvent() 时,每个线程返回的句柄值都不同......它们应该相同吗?
有没有更好的方法来确保它能够正常工作?
这是在 Windows XP 上使用 Visual Studio 2005
编辑:我做了更多检查,发现在生产者线程中调用 CreateEvent(第二个调用 CreateEvent)将 LastError 设置为 183 (ERROR_ALREADY_EXISTS), 但是 CreateEvent 仍然返回事件的句柄......给出了什么?它怎么会出错,因为它已经存在但仍然返回一个句柄?还是应该这样做?
【问题讨论】:
【参考方案1】:根据CreateEvent 的 MSDN 文档,
如果函数成功,则返回值是事件对象的句柄。如果指定的事件对象在函数调用之前已经存在,则函数返回现有对象的句柄,GetLastError 返回 ERROR_ALREADY_EXISTS。
根据您的描述,我认为您的操作没有问题。我没有看到任何迹象表明你做错了什么。不过,对我来说,我通常使用 CreateEvent() 创建一次事件,然后将句柄传递给我希望由该事件发出信号的线程。但您的方法在技术上没有任何问题。
您确实意识到 WaitForMultipleObjects() 返回句柄数组中第一个信号句柄的索引,对吧?例如,如果您的命名事件是列表中的第二个事件,但第一个句柄在绝大多数时间都发出信号(例如,通过快速作用线程或发出信号但从不重置的手动重置事件),WaitForMultipleObjects () 将始终返回 WAIT_OBJECT_0。换句话说,您的消费者线程永远不会看到您的命名事件已发出信号的事实,因为第一个句柄“总是”发出信号。如果是这种情况,请将您的命名事件放在列表的首位。
您不会碰巧将 WaitForMultipleObjects() 的 bWaitAll 参数设置为 TRUE,对吗?如果你这样做了,那么在函数返回之前,handles 数组中的所有句柄都已发出信号。
谁为您的命名事件调用 ResetEvent()?应该是消费者。它不会被某些第三方线程意外调用,是吗?
这些只是一些需要仔细检查的事情。如果事件仍未按预期运行,请将 WaitForMultipleObjects() 替换为 WaitForSingleObject() 以查看您的命名事件是否正确地向使用者线程发出信号。
希望这会有所帮助。
【讨论】:
【参考方案2】:如果您只是在一个进程中使用多个线程,为什么不将事件句柄从一个进程传递到另一个进程呢?据我所知,创建命名内核对象是为了在进程之间共享它们。
您也可以尝试使用 OpenEvent 函数打开已创建的事件。这可能会提供一些想法。
【讨论】:
MSDN 说 CreateEvent 在返回已经存在的句柄时准确地设置了 ERROR_ALREADY_EXISTS 的最后一个错误。我会更仔细地检查对象名称,也许您正在打开其他活动?或 WaitForMultipleObjects 调用。 我也不确定,但在我看来,同一事件在一个进程的不同线程中的事件句柄应该是相等的。它们在不同的过程中可能会有所不同。【参考方案3】:您的代码应该如您所描述的那样工作。如果在您尝试创建事件时该事件已经存在,您将获得现有事件的句柄。
每个线程的句柄不同,因此您不必担心它们是否不同(它们应该不同)。
我建议您稍微简化一下,看看事情是否按您期望的方式工作。您使用 WaitForMultipleObjects() 的事实告诉我您还有其他事情要做。如果您认为它不起作用,请摆脱其他东西,看看您是否可以解决。
【讨论】:
【参考方案4】:在单个进程中,您只需调用一次 CreateEvent 并共享所有线程中返回的句柄。
此外,除非您希望外部进程使用 OpenEvent 访问事件,否则您不需要命名事件。事实上,如果你为事件命名,你的程序只有一个副本能够成功调用 CreateEvent。
【讨论】:
以上是关于在 C++ 中创建/打开事件并检查它们是不是被触发的主要内容,如果未能解决你的问题,请参考以下文章
如何检查是不是在 Visual C++ 应用程序中的第三方 DLL 中创建了新线程