gpt4 book ai didi

multithreading - SetEvent ResetEvent WaitForMultipleObjectsEx-竞赛条件?

转载 作者:行者123 更新时间:2023-12-03 13:16:00 24 4
gpt4 key购买 nike

我无法理解PulseEvent或比赛条件。但是为了避免这种情况,我尝试改为SetEvent,每次尝试ResetEvent之前WaitForMultipleObjectsEx

这是我的流程:

  • 线程一-使用CreateEvent创建一个自动重置事件,然后生成并告诉线程2。
  • 线程一-告诉线程两个要运行。
  • 线程TWO将在事件上执行ResetEvent,然后立即在事件上启动WaitForMultipleObjectsEx和其他一些文件监视功能。如果WaitForMultipleObjectsEx返回,并且不是由于该事件引起的,则立即重新启动循环。如果WaitForMultipleObjectsEx返回,由于要通知事件,则不要重新启动循环。

  • 因此,现在请想象这种情况:
  • 线程两个-循环正在运行
  • 线程一-需要添加路径,因此它做到了(1)SetEvent,然后(2)向线程2发送另一条消息以添加路径,然后(3)向线程2发送消息以重新启动循环。
  • 除非我停止两个循环(由SetEvent完成),否则添加路径和重新启动循环的消息将不会进入线程TWO。线程2将看到由于事件该线程已停止,因此它不会重新启动循环。因此,它现在将获得消息以添加路径,因此它将添加路径,然后重新启动循环。
  • 线程一-需要停止线程,因此它执行(1)SetEvent,然后(2)等待消息线程2,当它收到该消息时将终止该线程。

  • 这样可以避免比赛情况吗?

    谢谢

    最佳答案

    假设循环需要连续两次中断。您正在想象在线程ONE和线程2上发生一系列类似的事件:

  • 线程ONE意识到第一个中断已完成。
  • 线程ONE发送一条消息,告诉两个重新启动等待循环。
  • 线程2读取消息“重新启动等待循环”。
  • 线程两次重置事件。
  • 线程两个开始等待。
  • 线程ONE现在意识到需要另一个中断。
  • 线程ONE设置事件以请求另一个中断。
  • 线程ONE发送与第二次中断有关的消息。
  • 线程2停止循环,接收有关第二次中断的消息。

  • 但是由于您无法控制两个线程之间的时序,因此可能会发生以下情况:
  • 线程ONE意识到第一个中断已完成。
  • 线程ONE发送一条消息,告诉两个重新启动等待循环。
  • 线程ONE现在意识到需要另一个中断。
  • 线程ONE设置事件以请求另一个中断。
  • 线程2读取消息“重新启动等待循环”。
  • 线程两次重置事件。
  • 线程两个开始等待。
  • 线程ONE发送有关第二次中断的消息,但是有两个没有监听!

  • 即使消息传递机制是同步的,所以直到两个读取消息后,ONE才会继续,它可能会以这种方式发生:
  • 线程ONE意识到第一个中断已完成。
  • 线程ONE发送一条消息,告诉两个重新启动等待循环。
  • 线程2读取消息“重新启动等待循环”,但随后被换出。
  • 线程ONE现在意识到需要另一个中断。
  • 线程ONE设置事件以请求另一个中断。
  • 线程两次重置事件。
  • 线程两个开始等待。
  • 线程ONE发送有关第二次中断的消息,但是有两个没有监听!

  • (显然,如果使用PulseEvent,可能会发生类似的情况。)

    一种快速的解决方案是对第二个事件使用第二个事件在适当的点发出信号,即在重置主事件之后但在等待它之前,但这似乎有些微不足道,并且也不能很好地概括。如果可以保证在足够的连续时间内不会出现两次中断,则可以选择忽略竞争条件,但是请注意,由于存在任何理论上的限制,因此很难对此进行推理。线程2在换出后恢复运行。

    各种选择取决于消息如何在线程之间传递以及任何其他约束。 [如果您可以提供有关当前实现的更多信息,我将相应地更新我的答案。]

    这是一些较明显的选项的概述。

    如果消息传递机制是同步的(如果线程ONE等待线程2等待线程2继续接收消息,然后继续),则使用单个自动重置事件应该可以正常工作。直到线程2收到重新启动循环消息后,线程ONE才设置事件。如果线程TWO开始等待时已经设置了事件,则意味着立即继承中发生了两次中断。两个永远不会停止等待不来的消息。 [此潜在的停顿是我能想到的,为什么您可能不想使用自动重置事件的唯一原因。如果您还有其他问题,请编辑问题以提供更多详细信息。]

    如果可以发送非阻塞的消息是可以的,并且您还没有被锁定在特定的解决方案中,那么以下任何一个选项都可能是明智的:
  • 用户模式APC(QueueUserAPC函数)提供了一种消息传递机制,该机制自动中断可警报的等待。
  • 您可以实现一个简单的队列(由关键部分保护),该队列使用事件指示是否有待处理的消息。在这种情况下,您可以安全地使用手动重置事件,前提是您只有在持有保护队列的相同关键部分时才对其进行操作。
  • 您可以将自动重置事件与任何类型的线程安全队列结合使用,前提是该队列允许您测试是否为空而不阻塞。这里的想法是线程ONE总是在设置事件之前将消息插入队列中,并且如果线程TWO看到设置了事件,但是事实证明队列为空,则忽略该事件。如果效率是一个问题,您甚至可以找到合适的无锁队列实现。 (我不建议您自己尝试。)

  • (也可以通过使用第二个事件对象使所有这些机制同步。)

    我不推荐以下方法,但是如果您碰巧已经在使用其中一种进行消息传递,则可以采用以下方法:
  • 如果您使用命名管道进行消息传递,则可以在线程TWO中使用异步I/O。线程2将在内部使用自动重置事件,在发出I/O调用时指定事件句柄,而Windows在I/O到达时设置事件句柄。从线程ONE的角度来看,只有一个操作。从线程2的角度来看,如果设置了事件,则肯定有一条消息。 (我相信这有点类似于your original approach,您只需要事先发出I/O调用即可,而不是之后发出。)
  • 如果您使用窗口队列进行消息传递,则MsgWaitForMultipleObjectsEx()函数可让您同时等待窗口消息和其他事件。


  • PS:

    PulseEvent的另一个问题是文档中提到的问题,它可能会发生:
  • 线程两个开始等待。
  • 线程2被Windows抢占,并且该线程上的所有用户代码停止运行。
  • 线程ONE触发事件。
  • 线程2由Windows重新启动,并重新开始等待。
  • 线程ONE发送一条消息,但两个没有监听。

  • (我个人对内核无法处理这种情况感到有些失望;我本以为它可以设置一个标志,说不应恢复等待。但是我只能假设有一个很好的理由说明这是不切实际的。)

    关于multithreading - SetEvent ResetEvent WaitForMultipleObjectsEx-竞赛条件?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39057933/

    24 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com