我有一個程序,有一些線環,可以發佈任務。其中一個線程循環是UI線程循環。它必須處理窗口消息以及發佈的任務,所以我發送WM_USER消息來喚醒調度循環中的線程。PostMessage的與WM_USER似乎沒有到達時MsgWaitForMultipleObjectsEx來檢查它
問題是,有時(特別是當有很多其他窗口消息,如WM_PAINT
或WM_RESIZE
)我的WM_USER
消息不會喚醒線程。看起來PostMessage
函數不會從MsgWaitForMultipleObjectsEx
調用喚醒線程,但我找不出原因。
這是什麼樣子的(有些意譯爲簡單起見):
#define HaveWorkMessage (WM_USER + 100)
class ThreadLoopUI {
public:
ThreadLoopUI()
: myHaveWork(0) {}
void PostTask(Task& aTask) {
{
ScopedLock lock(myMutex);
myTaskQueue.push_back(aTask);
}
ScheduleWork();
}
void ScheduleWork() {
if (InterlockedExchange(&myHaveWork, 1)) {
// No need to spam the message queue
return;
}
if (!PostMessage(myHWnd, HaveWorkMessage, reinterpret_cast<WPARAM>(this), 0)) {
std::cerr << "Oh noes! Could not post!" << std::endl;
}
}
void Run() {
for (;;) {
// SIMPLIFICATION, SEE EDIT BELOW
DWORD waitResult = MsgWaitForMultipleObjectsEx(0, NULL, (DWORD)INFINITE, QS_ALLINPUT, MWMO_INPUTAVAILABLE);
if (waitResult == WAIT_FAILED) {
std::cerr << "Well, that was unexpected..." << std::endl;
continue;
}
bool doWork = false;
MSG message;
if (PeekMessage(&message, NULL, 0, 0, PM_REMOVE)) {
if (message == HaveWorkMessage) {
doWork = true;
InterlockedExchange(&myHaveWork, 0);
}
// Send the message on to the window procedure
TranslateMessage(&message);
DispatchMessage(&message);
}
if (doWork) {
// Process all tasks in work queue
}
}
}
private:
HWND myHwnd;
Mutex myMutex;
std::vector<Task> myTaskQueue;
LONG volatile myHaveWork;
}
編輯:以上MsgWaitForMultipleObjectsEx
直接調用是一個簡化。其實,我調用看起來像這樣的功能:
void WaitForMessages() {
DWORD waitResult = MsgWaitForMultipleObjectsEx(0, NULL, (DWORD)INFINITE, QS_ALLINPUT, MWMO_INPUTAVAILABLE);
if (waitResult == WAIT_OBJECT_O) {
// Comment from the Chromium source:
// A WM_* message is available.
// If a parent child relationship exists between windows across threads
// then their thread inputs are implicitly attached.
// This causes the MsgWaitForMultipleObjectsEx API to return indicating
// that messages are ready for processing (Specifically, mouse messages
// intended for the child window may appear if the child window has
// capture).
// The subsequent PeekMessages call may fail to return any messages thus
// causing us to enter a tight loop at times.
// The WaitMessage call below is a workaround to give the child window
// some time to process its input messages.
MSG message = {0};
DWORD queueStatus = GetQueueStatus(QS_MOUSE);
if (HIWORD(queueStatus) & QS_MOUSE &&
!PeekMessage(&message, NULL, WM_MOUSEFIRST, WM_MOUSELAST, PM_NOREMOVE))
{
WaitMessage();
}
}
}
什麼是「不可見的到來」爲題??? – sashoalm 2013-02-21 10:05:10
@satuon:固定:) – 2013-02-21 10:51:43
您是否嘗試過'QS_ALLINPUT | QS_ALLPOSTMESSAGE'? – 2013-02-21 10:56:27