在多线程编程的领域中,经常会遇到各种挑战和问题。其中之一就是如何有效地在工作线程中使用消息循环。本文将介绍一个经常被忽视但非常有用的API——PostThreadMessage,以及如何在工作线程中实现消息循环。
在多年的多线程编程经验中,一直在思考PostThreadMessage的用途。尽管曾在UI线程中使用过它,但想知道它是否可以在工作线程中使用。相信每个API都有其存在的价值,否则微软的程序员们不会提供无用的功能。因此,创建了一个测试程序,在工作线程中加入了一个消息循环,并传递了NULL作为HWND参数:
#include <windows.h>
DWORD threadProc(LPVOID lParam) {
MSG msg;
while (GetMessage(&msg, NULL, 0, 0)) {
if (msg.message == WM_APP+1) {
MessageBoxA(NULL, "Hello", "From Thread", MB_OK);
}
DispatchMessage(&msg);
}
MessageBoxA(NULL, "Thread will close on pressing OK", "From Thread", MB_OK);
return 0;
}
int main() {
DWORD m_idThread;
CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)threadProc, NULL, 0, &m_idThread);
PostThreadMessage(m_idThread, WM_APP+1, 0, 0);
PostThreadMessage(m_idThread, WM_QUIT, 0, 0);
return 0;
}
这段代码展示了如何在工作线程中使用GetMessage和DispatchMessage来处理消息。GetMessage函数可以获取当前线程的消息,无论是窗口消息还是线程消息。
MSDN文档中提到:“如果hWnd为NULL,GetMessage将检索当前线程的任何窗口的消息,以及当前线程的消息队列中hwnd值为NULL的消息(参见MSG结构)。因此,如果hWnd为NULL,GetMessage将处理窗口消息和线程消息。”
在消息循环中,添加了一个消息处理器,它会等待特定的线程消息(例如WM_APP+1),然后执行一些操作,否则它将继续执行其工作。
PostThreadMessage API通过线程ID而不是窗口句柄(HWND)来工作。以下是MSDN文档中关于PostThreadMessage的描述:“将消息发送到指定线程的消息队列。它在不等待线程处理消息的情况下返回。”
BOOL WINAPI PostThreadMessage(
__in DWORD idThread,
__in UINT Msg,
__in WPARAM wParam,
__in LPARAM lParam
);
要获取线程ID,需要在创建线程时通过引用传递一个DWORD变量来收集新创建的工作线程的线程ID,如下所示:
DWORD m_idThread;
CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)threadProc, NULL, 0, &m_idThread);
同样,在_beginthreadex()API中也可以这样做,但是在_beginthread() API中没有这样的安排来检索线程ID。尽管有其他方法,但这里不讨论,因为这是离题的。现在有了工作线程的线程ID,可以使用PostThreadMessage向线程发送消息,例如发送一个问候:
PostThreadMessage(m_idThread, WM_APP+1, 0, 0);
以及指示线程退出:
PostThreadMessage(m_idThread, WM_QUIT, 0, 0);