【问题标题】:Behavior of WaitForMultipleObjects when multiple handles signal at the same time多个句柄同时发出信号时 WaitForMultipleObjects 的行为
【发布时间】:2016-07-26 08:49:58
【问题描述】:

假设:我用自动重置事件填充了一个句柄数组,并将其传递给 WaitForMultipleObjects 并使用 bWaitAll = FALSE。

来自 MSDN: “当 bWaitAll 为 FALSE 时,此函数会按从索引 0 开始的顺序检查数组中的句柄,直到其中一个对象发出信号。如果有多个对象发出信号,则该函数返回数组中第一个句柄的索引,其对象被发出信号。”

所以,现在如果多个对象发出信号,我将获得第一个对象的索引。我是否必须遍历我的阵列以查看是否有其他人发出信号?

现在我有一个循环,大致如下:

For ( ; ; )
{
WaitForMultipleObjects(…)
If  (not failed)
     Process object that called. 
     Remove the handle that signaled from the array.
     Compact the arrary.
}

【问题讨论】:

    标签: multithreading winapi events


    【解决方案1】:

    所以,现在如果有多个对象发出信号,我将获得第一个对象的索引。我必须循环吗 通过我的数组看看是否有其他人发出信号?

    为什么不直接回到 Wait() 中呢?如果多个对象发出信号,当你回来时它们仍然会发出信号。当然,如果您在等待对象数组中有一个非常快速地触发第一个对象,它将使其他对象挨饿;您所做的是按触发频率对等待对象数组中的对象进行排序,频率最低的优先。

    顺便说一句,在您使用无限 for() 的地方,您可以使用 goto。如果您确实没有离开循环,那么无条件 goto 最恰当地表达了您的意图。

    【讨论】:

    • 这是有效的解决方案。我需要弄清楚的关键是“如果多个对象发出信号,当你回来时它们仍然会发出信号。”如果我不必担心饥饿,那么我最初的解决方案就可以了。
    • 是的。 WaitForMultipleObjects() 从 0 开始扫描句柄数组,并在找到信号句柄后立即返回。只有第一个找到的句柄被重置为无信号状态;其他的都没有动过。
    【解决方案2】:

    是的。一种替代方法是您可以对每个句柄执行 WaitForSingleObject(handle, 0) 操作,该句柄将立即返回并指示它们是否已发出信号。

    编辑:这是我的意思的示例伪代码:

    ret = WaitForMultipleObjects()
    if (ret >= WAIT_OBJECT_0 && ret < WAIT_OBJECT_0 + (count))
    {
        firstSignaled = ret - WAIT_OBJECT_0;
    
        // handles[firstSignaled] guaranteed signalled!!
    
        for (i = firstSignaled + 1; i < count; i++)
        {
            if (WaitForSingleObject(handles[i], 0) == WAIT_OBJECT_0)
            {
               // handles[i] Signaled!
            }
        }
    }
    

    【讨论】:

    • 是的,在 waitformultipleobjects 调用之后执行此操作
    • 这个答案的问题是你基本上用那个 WaitForSingleObject 打开了 bWaitAll。我不想等待所有的句柄,只为那些发出信号的句柄提供服务。
    • 超时时间为 0 表示 WaitForSingleObject 不等待。它检查信号状态并立即返回 WAIT_OBJECT_0 或 WAIT_TIMEOUT。还是我误解了你的说法?
    • 你的意思是正确的。我错了。来自 MSDN “如果 dwMilliseconds 为零,则该函数测试对象的状态并立即返回”。在我评估它们之后处理该信号会发生什么?我想他们会一直收到信号,当我再次点击 wait multiple 时我会接他们。
    • 这取决于句柄的类型。手动重置事件将保持信号状态并需要重置。自动重置事件将返回未发出信号。互斥量将在 WaitForSingleObject 调用之后获取 - 依此类推。
    【解决方案3】:

    您可能还有一个选择是使用RegisterWaitForSingleObject。这个想法是,您在回调函数的辅助数组中标记事件的信号状态,然后发出用于唤醒主线程(在主事件上调用 WaitForSingleObject)的主事件。

    显然,您必须注意确保辅助数组不受主线程访问,但它会起作用。

    【讨论】:

      【解决方案4】:

      只有结束等待的自动重置事件(返回其索引)才会被重置。如果等待超时,则不会重置任何事件。

      cf https://blogs.msdn.microsoft.com/oldnewthing/20150409-00/?p=44273

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2023-03-23
        • 1970-01-01
        • 2015-07-17
        • 2016-03-26
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多