2014-09-18 2 views
3

Следующий глобальный поток Hook занимает слишком много CPU, если я не добавлю Sleep (10), есть другое решение, чем Sleep (10 мс) - сон не выглядит оптимальным решением для производительности моего приложения. Если я добавлю слишком много сна, это не замедлит мышь.Глобальная цепочка потоков занимает слишком много CPU, как исправить?

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; 
+0

Есть ли Обоснованием задержки 10 мс? Как правило, отказ от текущего тайм-листа выполняется с помощью 'Sleep (0)'. –

+0

Доходность вместо сна (0) также должна работать. –

+0

Какова цель вашей темы? И как вы положили свой крючок в Thread? –

ответ

5

Попробуйте что-то больше, как это вместо:

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; 
+0

Вы можете безопасно обрабатывать возвращаемое значение GetMessage как BOOL в этом случае –

+1

'BOOL' - это псевдоним для' LongBool', который обрабатывает -1 как True. Если 'GetMessage()' возвращает -1, и вы используете цикл while в GetMessage(), он не будет ломаться при ошибке. Даже MSDN объясняет это конкретное условие в документации 'GetMessage()' и говорит, что не записывайте свой код таким образом. Следовательно, явная проверка на -1 (тем более, что я хочу вызывать 'RaiseLastOSError()' так или иначе, поскольку 'GetLastError()' сообщает код ошибки, когда 'GetMessage()' возвращает -1). –

+0

Документы говорят: * Если есть ошибка, возвращаемое значение равно -1. Например, функция завершается с ошибкой, если hWnd является недопустимым дескриптором окна или lpMsg является недопустимым указателем. * Ни одно из этих условий не может иметь место здесь, и поэтому возвращаемое значение никогда не будет равным -1. Раймонд объясняет: http://blogs.msdn.com/b/oldnewthing/archive/2013/03/22/10404367.aspx Воспользовавшись этим, вы значительно упростите код. –

6

Ваш цикл сообщений - это цикл занятости. Вы должны использовать GetMessage вместо PeekMessage. Это потому, что GetMessage блокируется, пока сообщения не добавляются в очередь.

Вы отмечаете в комментариях, что GetMessage блокируют, что нарушает ваш код завершения. Поступайте с этим, разместив сообщение в потоке после его завершения. Либо WM_NULL в качестве общего пробуждения, либо WM_QUIT как явная инструкция для выхода из цикла сообщений.

+0

Спасибо, GetMessage() отлично от точки зрения производительности, но имеет серьезную проблему, нить не может быть прервана этим! Кажется, что «Terminated» не происходит, когда я вызываю th.Terminate; – Tom

+0

- * «нужно использовать GetMessage *» - это не обязательно, 'WaitMessage' может использоваться для блокировки, когда' PeekMessage' возвращает false. –

+0

@Sertac Да, потребность слишком сильна. Тем не менее, Wait/Peek вряд ли будет предпочтительнее. –

Смежные вопросы