delphi – Postmessage和sendmessage的替代方案
我有一个程序正在使用几个线程执行一些任务.每个线程都有一堆要执行的任务.在执行其中的一个后,每个thred将调用一条发送消息到主屏幕来更新日志.
现在我有六万个任务,每个线程一万个 – 六个线程 – 执行每个任务线程后,调用帖子消息.但是由于这些帖子消息,我的应用程序变得非常繁忙,看起来像挂起. 如果我删除帖子消息…每件事情都可以正常工作.但我不能直接调用程序,因为它使用ui控件和ui控件不是线程安全的,直接从线程调用过程将导致其他错误. 那么还有什么替代方案可以用于postmessage和发送消息. 谢谢, 解决方法
问题是发布邮件有两个消息队列.其结果是您发布的消息是
always processed before any
Paint ,Input ,or Timer messages.
这意味着您正在使用几十万条消息淹没消息队列.这些消息将始终在绘制和用户消息之前被处理 – 使您的应用程序看起来挂起. 解决这个问题的常用方法是使用定时器;您的代码开始时间非常短(例如0 ms)定时器.
定时器触发时,发送WM_TIMER消息.任何输入和绘制消息后,将始终处理此消息;使您的应用程序显示响应. 设置计时器的另一个优点是它强制您“排队”所有在(线程安全)列表中处理的项目.您将几千个工作项目合并成一个“定时器”,从而节省系统不必生成和处理数千个不必要的消息. 奖金喋喋不休
更新:你不应该有一个定时器轮询,这只是浪费和错误.你的线程应该“设置一个标志”(即定时器).这允许您的主线程实际上空闲,只有当有事要做的时候醒来. 更新二: 证明消息生成顺序不被保留的伪代码: //Code is public domain. No attribution required. const WM_ProcessNextItem = WM_APP+3; procedure WindowProc(var Message: TMessage) begin case Message.Msg of WM_Paint: PaintControl(g_dc); WM_ProcessNextItem: begin ProcessNextItem(); Self.Invalidate; //Invalidate ourselves to trigger a wm_paint //Post a message to ourselves so that we process the next //item after any paints and mouse/keyboard/close/quit messages //have been handled PostMessage(g_dc,WM_ProcessNextItem,0); end; else DefWindowProc(g_dc,Message.Msg,Message.wParam,Message.lParam); end; end; 即使在生成WM_PAINT消息(即无效)后生成WM_ProcessNextItem,WM_PAINT也不会被处理,因为在它之前总是有一个发送的消息.而as MSDN says,只有没有其他帖子的消息才会出现. 更新三:是的,只有消息队列,但这就是为什么我们不在乎:
旧的新事物,Windows的进化中的实践发展 更容易想象有两个消息队列.在“第一”队列为空之前,将不会读取“第二”中的消息;而OP绝对不会让第一个队列流失.因此,第二个队列中的“paint”和“input”消息都不会被处理,从而使应用程序看起来挂起.
更新四 问题不一定是您的邮件“淹没”输入队列.您的应用程序可能无法响应,只有一条消息.只要你有一个帖子在队列中,它将在任何其他消息之前被处理. 想象一下,一系列事件发生: 鼠标移动(WM_MOUSEMOVE) 您的应用程序的main message loop(调用GetMessage)将不会按照发生的顺序接收消息.它将检索WM_ProcessNextItem消息.这将从消息队列中移除消息,留下: > WM_MOUSEMOVE 处理您的项目时,用户可以更多地移动鼠标,并随机点击: > WM_MOUSEMOVE 响应您的WM_ProcessNextItem,您再发送一个消息给自己.您这样做是因为您希望先处理未完成的邮件,然后再继续处理更多的项目.这将添加另一个发送消息到队列中: > WM_MOUSEMOVE 问题开始变得明显.下一次调用GetMessage将检索WM_ProcessNextItem,使应用程序有一个积压的油漆和输入消息: > WM_MOUSEMOVE 解决方案是利用消息的乱序处理.发布的消息始终在绘制/输入/定时器消息之前处理:不要使用已发布的消息.您可以将消息队列分为两组:发布消息和输入消息.而不是导致“发布”消息队列从不允许为空的情况: Posted messages Input messages ================== ===================== WM_ProcessNextItem WM_MOUSEMOVE WM_LBUTTONDOWN WM_LBUTTONUP WM_PAINT 你使用WM_TIMER消息: Posted messages Input messages ================== ===================== WM_MOUSEMOVE WM_LBUTTONDOWN WM_LBUTTONUP WM_PAINT WM_TIMER
重要的是要注意,你不是用计时器进行轮询,这将是坏的.相反,您正在触发一次性定时器作为生成WM_TIMER消息的机制.您这样做是因为您知道定时器消息不会优先于画面或输入消息. 使用定时器具有另一个可用性优势.在WM_PAINT,WM_TIMER和输入消息之间,它们也有无序处理: >输入消息,然后 如果您使用计时器通知您的主线程,还可以保证您更快地处理油漆和用户输入.这样可以确保您的应用程序保持响应.这是一个可用性增强,你可以免费获得它. (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |