gpt4 book ai didi

multithreading - 如何保持线程的消息泵 react 性

转载 作者:行者123 更新时间:2023-12-03 15:49:23 29 4
gpt4 key购买 nike

我正在实现一个需要以下功能的线程:

  1. 及时响应终止请求
  2. 推送消息
  3. 在等待消息时保持对 SendMessage 请求的响应

我对消息泵的初始实现使用了 GetMessage,如下所示:

while not Terminated and GetMessage(Msg, 0, 0, 0) do
begin
TranslateMessage(Msg);
DispatchMessage(Msg);
end;

我发现的问题是,除非有消息,否则 GetMessage 将永远不会返回。这意味着,如果消息事件较少,可能需要相当长的一段时间才能再次检查已终止

我的第二个实现(受到 this answer 的启发)使用 MsgWaitForMultipleObjects 在检查之前等待消息存在(因为它有超时)

while not Terminated do
begin
if MsgWaitForMultipleObjects(0, nil^, False, 1000, QS_ALLEVENTS) = WAIT_OBJECT_0 then
begin
while PeekMessage(Msg, 0, 0, 0, PM_REMOVE) do
begin
TranslateMessage(Msg);
DispatchMessage(Msg);
end;
end;
end;

我发现的问题是 MsgWaitForMultipleObjects 在等待时阻塞线程。因此,当通过 SendMessageTimeout 向线程发送消息时,它会超时,而使用 GetMessage 时不会超时。

想到的解决方案是返回到 GetMessage 实现,但添加一个计时器以确保 WM_TIMER 消息每秒重置循环。

这真的是唯一的方法吗?看来应该有一些更好的方法来让线程在等待消息时保持响应。

最佳答案

My initial implementation of the message pump used GetMessage like:

while not Terminated and GetMessage(Msg, 0, 0, 0) do
begin
TranslateMessage(Msg);
DispatchMessage(Msg);
end;

The problem I found with that, is that GetMessage will never return unless there is a message. Meaning, if there is low message activity, it may be quite a while before it checks Terminated again.

您可以覆盖线程的虚拟 TerminatedSet()方法通过 PostMessage()PostThreadMessage() 向队列发布消息以“唤醒”GetMessage() 如果被阻止。

或者,让你的线程构造函数创建一个 TEvent对象,并在线程的析构函数中释放它。然后让 TermatedSet() 发出该事件的信号。然后,您的循环可以使用 MsgWaitForMultipleObjects() 同时等待消息队列和事件。返回值将告诉您是否通过消息或事件满足了等待。

My second implementation (inspired by this answer) used MsgWaitForMultipleObjects to wait until a message exists before checking (since it has a timeout)

while not Terminated do
begin
if MsgWaitForMultipleObjects(0, nil^, False, 1000, QS_ALLEVENTS) = WAIT_OBJECT_0 then
begin
while PeekMessage(Msg, 0, 0, 0, PM_REMOVE) do
begin
TranslateMessage(Msg);
DispatchMessage(Msg);
end;
end;
end;

The problem I've found with this, is that MsgWaitForMultipleObjects blocks the thread while it waits. So, when a message is sent to the thread via SendMessageTimeout, it times out, where it doesn't when using GetMessage.

SendMessage...() 系列函数将直接将消息传递到目标窗口的消息过程,完全绕过消息队列。因此 MsgWaitForMultipleObjects()(Get|Peek)Message() 永远不会报告来自 SendMessage...() 的已发送消息,仅来自 PostMessage()PostThreadMessage()发布消息(或合成消息,如 WM_TIMERWM_PAINT 等)。但是,当跨线程边界发送消息时,接收线程仍然需要执行消息检索调用(即(Get|Peek)Message()),以便发送消息实际传递给窗口过程。

The solution that comes to mind is to go back to the GetMessage implementation, but add a timer to make sure a WM_TIMER message resets the loop every second.

在线程内,最好使用 waitable timer而不是 WM_TIMER,那么您可以通过 MsgWaitForMultipleObjects() 使用计时器。但实际上,将 GetMessage()WM_TIMER 一起使用与 MsgWaitForMultipleObjects() 与超时一起使用之间几乎没有什么区别,因此没有必要创建计时器浪费系统资源。

关于multithreading - 如何保持线程的消息泵 react 性,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59076128/

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