【问题标题】:UI + Worker Multithreading issueUI + Worker 多线程问题
【发布时间】:2011-12-11 21:26:19
【问题描述】:

我无法在后台执行搜索操作,并在列表框内的前台向用户显示结果。

程序使用SendMessage 将查询结果发送回GUI。

当程序关闭时,GUI 将一个全局(易失)变量标记为“已完成”,并使用MsgWaitForMultipleObjects 等待线程句柄,加入线程。

当我中断程序时,我看到一个死锁:GUI 正在等待后台线程终止,而后台线程在 SendMessage 中等待。

当我对MsgWaitForMultipleObjects 使用 100 毫秒超时并在循环中调用它时,仍然会发生这种死锁,使用QS_ALLINPUT。我不知道为什么。

这个设计是否正确?有没有更好的方法来等待线程终止?
如果不是,那是什么问题?

【问题讨论】:

  • 你能用PostMesage代替SendMessage吗?
  • @AndyT:我不这么认为——搜索线程比 GUI 线程运行得快,所以我可能会超出 PostMessage 在内部执行的任何消息的缓冲。
  • 为什么需要等待线程终止呢?有什么压倒一切的理由吗? PostMessage 可以排队 10000 条消息,但你不应该接近它。提供流控制的简单方法是在启动时创建一个小型对象/结构/任何您用于数据传输的池(即,一个带有 O/S/W 的生产者-消费者队列)。您的搜索线程从池中提取 O/S/W,填充它们并 PostMessages 关闭它们。在 GUI 线程中处理完消息后,将它们推回池中。如果搜索线程试图溢出,它将被阻塞。
  • @MartinJames:好吧,当程序关闭时,我有点需要它终止,哈哈......

标签: c multithreading winapi background-thread


【解决方案1】:

您需要一个双缓冲方案以避免超出消息队列。像这样布置它:

线程 1 执行搜索并使用 PostMessage 发送结果。

线程 2 读取消息队列,选择性地删除搜索结果消息,并将它们存储在可以处理任意数量条目的基于内存的内部队列中。

线程 3 从内部队列中读取结果并显示出来。

请注意,您需要具有互斥保护的队列的 get/put API,以防止线程 2 和 3 相互踩踏。

【讨论】:

  • 我将如何 (1) 通知线程它应该终止,然后 (2) 等待线程终止而不发生死锁?
  • 您可以使用任何类型的信号机制(例如,信号量)来通知线程终止,然后简单地对其线程句柄执行 WaitForSingleObject。由于它使用的是 PostMessage 而不是 SendMessage,因此不会产生死锁。
  • 哦,我明白了...不过,我不能 100% 确定 PostMessage 是否会出现僵局,因为我也不认为 SendMessage 会出现任何僵局(因为我设置了超时,并指定了QS_ALLINPUT)。但这是一个想法,谢谢。
  • @Mehrdad:您应该期待与SendMessage 发生死锁,因为“SendMessage 函数调用指定窗口的窗口过程并且在窗口过程处理完之前不会返回消息。”
  • @CareyGregory:不需要 3 线程方法,因为同样可以使用 2 线程来完成。看我的回答。
【解决方案2】:

这是经典的consumer/producer pattern。不要使用线程消息队列,使用自己的同步队列,最好是固定大小的。您的消费者(UI 线程)将按需减慢您的搜索线程。或者,如果您检测到同步队列太大,您可以过滤搜索结果以适应 UI 线程速度。

【讨论】:

    【解决方案3】:

    MsgWaitForMultipleObjects 说“你有一条消息”之后,你必须去处理这条消息。你get only one chance - 如果你没有这样做(并且只是循环回来并再次调用MsgWaitForMultipleObjects),消息将不会被处理并且你不会收到任何进一步的通知。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-04-02
      • 2016-06-05
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多