在 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++ 中创建/打开事件并检查它们是不是被触发的主要内容,如果未能解决你的问题,请参考以下文章

在 NestedList 中创建项目后立即触发的事件

如何检查是不是在 Visual C++ 应用程序中的第三方 DLL 中创建了新线程

在 C++ 中触发事件并在 C# 中处理它们

在 Azure Blob 容器中创建两个文件时,如何在 Azure 数据工厂中创建事件触发器?

在 RowDatabound 中创建的按钮不会触发点击事件

检查模型是不是在 before_save 事件中被修改或创建