【问题标题】:AutoResetEvent and COM ObjectsAutoResetEvent 和 COM 对象
【发布时间】:2010-12-02 04:04:49
【问题描述】:

我注意到 AutoResetEvent 在 WaitOne() 调用过程中(有时)完全冻结了消息循环,甚至有效地阻止了信号消息。

IE:

  1. (UI)新线程产生
  2. (UI) 代码调用 WaitOne();超时:10s
  3. (T2) 线程打开设备,调用 Set()
  4. (UI) WaitOne 阻止消息循环
  5. (UI) WaitOne 超时,代码继续执行
  6. (UI)主窗口接收信号并继续(但 WaitOne 失败)

有什么想法吗?

编辑:添加 UI/T2 以指定线程。另外,我正在尝试将第 3 方库变为同步。打开设备涉及一个 Open() 调用,该调用反过来产生一个 OpenOK 或 OpenFailed 事件,我正在尝试进行一个 bool Open() 调用,该调用根据产生的事件返回 true/false。

【问题讨论】:

  • 您能否在上述步骤中添加每个操作在哪个线程上运行的前缀(可能使用 UI、T1、T2 等)。在你的描述中很难理解哪个线程是哪个线程。
  • 另外,如果你愿意,你可以在创建它时将 AutoResetEvent 的状态设置为发出信号,这样你就不会在第一次调用时超时(如果你想要的话)-> AutoResetEvent e = AutoResetEvent(true);
  • 定义“打开设备”。您可能希望确保打开设备不依赖于消息循环正在处理的任何消息。
  • 不,只有 COM 事件。其余的只是硬件。

标签: c# com multithreading message-loop


【解决方案1】:

... 甚至有效地阻止了信号消息。

您不能“阻止信号”发送,您只能阻止其他线程到达设置事件的位置。等待句柄根本不需要消息泵。

我唯一能想到的可能是有问题的 COM 对象与 UI 线程相关联。访问 COM 对象可能会尝试从 T2 调用回等待 T2 执行某些操作的 UI 线程(死锁)。要查看这是否确实是问题,请确保您没有在 UI 线程上创建或访问 COM 对象。

【讨论】:

  • 如果我在 UI 线程上创建它怎么办?你会推荐什么?同样,您将如何在另一个线程上创建它?
  • 几个选项...简单的答案是只使用 UI 线程和 Timer 事件来轮询 COM 对象直到完成。
【解决方案2】:

您可能会发现 this SO 帖子“在继续处理时等待主线程”
还可以从 MSDN 签出 Calling Synchronous Methods Asynchronously

【讨论】:

    【解决方案3】:

    这是竞争条件的结果。问题是第 3 步可能发生在第 2 步之前,因为它们位于不同的线程上。因为您使用的是 AutoResetEvent,所以在调用 WaitOne 时,该事件已被重置。

    因为这个问题,只要有可能,我一般都会尽量避免使用 AutoResetEvents 来支持 ManualResetEvents。

    ManualResetEvent 的事件顺序是(我将事件 2 列为 2a 和 2b 以证明它们的操作顺序无法保证):

    1. 新线程产生
    2. 一个。原始线程调用 WaitOne();湾。新线程调用 Set();
    3. 原线程唤醒。
    4. 原线程调用Reset();

    【讨论】:

    • 这不是竞争条件。在我一直在测试的特定情况下,它不是立即的——它需要几秒钟。无论哪种方式,如果使用 ManualResetEvent 而不是 Auto,这将如何改变?
    • 延迟并不与我看到的竞争条件相反。 ManualResetEvents 将保持设置,直到它们被明确重置。在调用 WaitOne 之前,您的 AutoResetEvent 会自行重置。这就是为什么 WaitOne 永远不会被触发的原因。
    • ManualResetEvent 也会出现同样的问题。我确定消息泵也被阻止了,但我不知道如何处理。 :(
    • @Kennet - 根据 MSDN,AutoResetEvent 保持有信号状态,直到释放单个等待线程,然后自动返回到无信号状态。如果没有线程在等待,则状态会无限期地保持信号状态。如果线程在 AutoResetEvent 处于信号状态时调用 WaitOne,则线程不会阻塞。 AutoResetEvent 立即释放线程并返回到无信号状态。所以在调用 WaitOne 之前它不会重置(在这种情况下它是事先设置好的,它不应该阻塞);还有其他事情发生。
    • @SwDevMan81 - 你似乎是对的。我在那里叫错了树。
    猜你喜欢
    • 2011-06-27
    • 2014-09-01
    • 2012-12-15
    • 1970-01-01
    • 2014-12-27
    • 2010-12-13
    • 1970-01-01
    • 2011-07-25
    • 1970-01-01
    相关资源
    最近更新 更多