Delphi 全局钩子线程占用太多CPU,如何修复?
下面的全局钩子线程占用了太多CPU,除非我在那里添加睡眠(10), 除了睡眠(10毫秒)还有其他解决方案吗?对于我的应用程序的性能来说,睡眠看起来不是一个最佳的解决方案。如果我加了太多的睡眠,它不是也会减慢鼠标的速度吗Delphi 全局钩子线程占用太多CPU,如何修复?,delphi,Delphi,下面的全局钩子线程占用了太多CPU,除非我在那里添加睡眠(10), 除了睡眠(10毫秒)还有其他解决方案吗?对于我的应用程序的性能来说,睡眠看起来不是一个最佳的解决方案。如果我加了太多的睡眠,它不是也会减慢鼠标的速度吗 procedure THookThread.Execute; begin hookhandle := SetWindowsHookEx(WH_MOUSE_LL, @LowLevelMouseHook, Hinstance, 0); while
procedure THookThread.Execute;
begin
hookhandle := SetWindowsHookEx(WH_MOUSE_LL, @LowLevelMouseHook, Hinstance, 0);
while not Terminated do
begin
MessageLoop;
// Sleep(10);
end;
UnHookWindowsHookEx(hookhandle);
hookhandle := 0;
end;
procedure THookThread.MessageLoop;
var
msg: TMsg;
begin
while PeekMessage(msg, 0, 0, 0, PM_NOREMOVE) do
begin
TranslateMessage(msg);
DispatchMessage(msg);
end;
end;
您的消息循环是一个忙循环。您应该使用
GetMessage
而不是PeekMessage
。这是因为GetMessage
阻塞,直到消息添加到队列中
您在注释中注意到,
GetMessage
阻塞了终止代码。通过在终止后向线程发送消息来处理该问题。WM_NULL
作为常规唤醒,或WM_QUIT
作为退出消息循环的显式指令 试试类似的方法:
procedure THookThread.Execute;
var
msg: TMsg;
ret: LongInt;
begin
//create the message queue...
PeekMessage(msg, 0, WM_USER, WM_USER, PM_NOREMOVE);
hookhandle := SetWindowsHookEx(WH_MOUSE_LL, @LowLevelMouseHook, Hinstance, 0);
if hookhandle = 0 then RaiseLastOSError;
try
while GetMessage(msg, 0, 0, 0) and (not Terminated) do
begin
TranslateMessage(msg);
DispatchMessage(msg);
end;
finally
UnHookWindowsHookEx(hookhandle);
hookhandle := 0;
end;
end;
procedure THookThread.Stop;
begin
Terminate;
PostThreadMessage(ThreadID, WM_QUIT, 0, 0);
end;
10毫秒延迟背后有什么原因吗?通常,放弃当前时间片是通过
Sleep(0)
完成的。使用Yield而不是Sleep(0)也可以。线程的用途是什么?你怎么把钩子放在一条线里了?为什么不直接用GetMessage
而不是PeekMessage
?前者自然会阻塞,直到有消息可用,绕过繁忙的循环和相关的高CPU使用率。这不是对你问题的回答,但我强烈建议你寻找一个能满足你需要的组件,而不是重新发明这个轮子。我自己在感谢方面也有很好的经验,GetMessage()从性能的角度来看是非常好的,但是有一个主要的问题,线程不能用这个来终止!当我调用Terminate时,似乎没有出现“Terminate”;-“需要使用GetMessage”-这不是强制性的,WaitMessage
可用于在PeekMessage
返回false时阻止。@Sertac是的,需要太强烈。也就是说,等待/偷看很难成为首选。@Tom所以不要使用Terminate。。。您有一个消息循环,请改为发布一条消息。谢谢您的帮助,代码现在可以运行了。但是,我要感谢有完整代码的,很抱歉。您可以安全地将GetMessage返回值视为BOOL。在本例中,BOOL
是LongBool
的别名,它将-1视为True。如果GetMessage()
返回-1,并且您使用while-GetMessage()
循环,则它不会在失败时中断。甚至MSDN也在GetMessage()
文档中解释了这个特定条件,并说不要这样编写代码。因此,显式检查-1(特别是因为我无论如何都要调用raiselastserror()
,因为GetLastError()
在GetMessage()
返回-1时报告错误代码)。例如,如果hWnd是无效的窗口句柄或lpMsg是无效的指针,则函数将失败。这两种情况在这里都不可能发生,因此返回值永远不会为-1。雷蒙德解释说:利用这一点,你可以大大简化代码。我原以为你会很高兴了解这一点,而不是不屑一顾。我知道我很感激你多次教我一些东西。我以前读过那篇文章,这次我只是不记得那个特别的细节。我不经常编写消息循环,当我这样做时,我通常不会对它们使用GetMessage()
。