不使用SendMessage()从其他线程访问UI控件的原因?

use*_*812 0 winapi multithreading

我已经读过SendMessage()不应该用来从其他线程访问UI控件,但是我不知道我知道为什么,我能想到的唯一原因是因为SendMessage()是阻塞调用,那么它可能会在某些情况下导致死锁.

但这是不使用它的唯一原因吗?


编辑:文章有关会谈的理由不使用SendMessage(),但我不觉得这是非常明确的(它是用于.NET).

Han*_*ant 7

最好记住,你编写正确代码的几率并不是很好.通用的建议是不要这样做! 这是从来没有必要,在Windows GUI程序的UI线程是完全结构化,使之简单,以允许在另一个线程或进程中影响程序的UI运行的代码.消息循环的要点,生产者 - 消费者问题的通用解决方案.PostMessage()是你利用它的武器.

在你继续前进之前,首先要考虑一个在使用SendMessage时很难解决的简单问题.如何安全正确地关闭窗户?

鉴于您需要关闭窗口的确切时刻是完全不可预测的,并且与工作线程的执行完全不同步.用户关闭它,或要求UI线程终止,您需要确保线程已退出并停止调用SendMessage,然后才能实际关闭窗口.

直观的方法是在WM_CLOSE消息处理程序中发出事件信号,要求线程停止.等待它完成,然后窗口可以关闭.直观,但它不起作用,它会使你的程序陷入僵局.有时候,并不总是很难调试.当线程无法检查事件时出错,因为它卡在SendMessage调用中.由于UI线程正在等待线程退出,因此无法完成.工作线程无法继续,UI线程无法继续.一个"致命的拥抱",你的程序将挂起并需要被强行杀死.死锁是一个标准的线程错误.

你会喊道,"我会使用SendMessageTimeout!" 但是你为uTimeout参数传递了什么?你如何解释ERROR_TIMEOUT错误?对于一个UI线程来说,一段时间内是紧张性精神紧张是非常常见的,当然你之前已经看过"鬼窗口",在标题栏中显示"无响应".因此,除非使uTimeout非常大,否则ERROR_TIMEOUT无法可靠地指示UI线程正在尝试关闭.至少10秒.这有点起作用,但偶尔在出口处停留10秒并不是很漂亮.

解决所有消息的这种问题,而不仅仅是WM_CLOSE.WM_PAINT应该是下一个,另一个非常非常难以彻底解决的问题.您的工作线程要求在UI线程调用EndPaint()之前一毫秒更新显示.因此从不显示更新,它只是迷路了.线程竞争,另一个标准线程错误.

第三个经典的线程错误是火管问题.当您的工作线程产生的结果比UI线程可以处理它们更快时,就会发生这种情况.非常常见的UI更新非常昂贵.易于检测,很难解决,并且在发生时难以预测.由于UI会冻结,因此易于检测,UI线程会烧掉100%的核心,试图跟上消息速率.它不再能够解决它的低优先级任务了.喜欢画画.不顺心当您使用SendMessage函数或PostMessage的.在后一种情况下,您将填充消息队列以达到容量.它包含10000个未处理的消息后开始失败.

简而言之,是的,SendMessage()是线程安全的.但线程安全不是传递属性,它不会自动使您自己的代码线程安全.当你使用线程时,你仍然会遇到所有可能出错的事情.僵局,种族,火灾.害怕穿线的野兽.

  • 所以最好不要使用`SendMessage()`.但是`PostMessage()`是异步的,所以如何使用它来获取UI控件的内容! (2认同)
  • 你不应该编写这样的代码,它是另一个线程种族bug.在启动工作线程之前从UI收集信息.禁用该窗口,以便用户无法更改文本并知道编辑无法正常工作.当工人完成时重新启用窗口. (2认同)
  • @ user4582812您问了一个广泛而一般的问题.得到了同样性质的答案.接下来,您开始询问您的应用的具体细节,只有您知道.如果你想询问具体细节,可以这样做,但是你提出一般性问题似乎很奇怪,然后对你的具体问题发表评论.您在第一条评论中得出的结论非常错误.世界不会分裂成通过调用`SendMessage`解决的问题,以及通过调用`PostMessage`解决的问题.这是一种错误的二分法. (2认同)