1. SendMessage 潜在问题
- 阻塞问题:SendMessage 是同步消息发送机制,调用线程会等待目标窗口处理完消息后才继续执行。在高并发场景下,如果目标窗口处理消息时间较长,调用线程会被阻塞,可能导致整个应用程序假死。例如在一个处理多个并发任务的线程中调用 SendMessage 向某个窗口发送消息,若该窗口消息处理函数正在执行复杂计算,此线程会一直等待,影响其他任务的执行。
- 死锁风险:当两个或多个线程相互等待对方处理消息时,可能会发生死锁。比如线程 A 向线程 B 所在窗口发送消息,而线程 B 又在等待线程 A 处理另一个消息,就会形成死锁。
2. PostMessage 潜在问题
- 消息丢失:PostMessage 是异步消息发送,将消息放入目标窗口的消息队列后立即返回。在高并发环境下,如果消息队列已满,新的消息可能会被丢弃,导致消息丢失。例如在短时间内大量并发线程向同一窗口发送大量消息,消息队列可能无法容纳而丢失部分消息。
3. 优化措施及 C++ 代码示例
- 针对 SendMessage 阻塞问题:
- 多线程处理:将 SendMessage 调用放在单独的线程中执行,避免阻塞主线程。以下是简单示例代码:
#include <windows.h>
#include <thread>
#include <iostream>
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
PSTR szCmdLine, int iCmdShow)
{
static TCHAR szAppName[] = TEXT("MessageTest");
HWND hwnd;
MSG msg;
WNDCLASS wndclass;
wndclass.style = CS_HREDRAW | CS_VREDRAW;
wndclass.lpfnWndProc = WndProc;
wndclass.cbClsExtra = 0;
wndclass.cbWndExtra = 0;
wndclass.hInstance = hInstance;
wndclass.hIcon = LoadIcon(NULL, IDI_APPLICATION);
wndclass.hCursor = LoadCursor(NULL, IDC_ARROW);
wndclass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
wndclass.lpszMenuName = NULL;
wndclass.lpszClassName = szAppName;
if (!RegisterClass(&wndclass))
{
MessageBox(NULL, TEXT("This program requires Windows NT!"),
szAppName, MB_ICONERROR);
return 0;
}
hwnd = CreateWindow(szAppName, TEXT("SendMessage Test"),
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, CW_USEDEFAULT,
CW_USEDEFAULT, CW_USEDEFAULT,
NULL, NULL, hInstance, NULL);
ShowWindow(hwnd, iCmdShow);
UpdateWindow(hwnd);
std::thread([&hwnd]() {
SendMessage(hwnd, WM_USER + 1, 0, 0);
}).detach();
while (GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return msg.wParam;
}
LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message)
{
case WM_USER + 1:
// 处理自定义消息
std::cout << "Received custom message in WndProc" << std::endl;
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hwnd, message, wParam, lParam);
}
return 0;
}
- 针对 SendMessage 死锁问题:
- 消息优先级和超时机制:可以给消息设置优先级,优先处理关键消息,避免死锁。同时设置超时,如果在规定时间内没有收到响应,取消等待并进行相应处理。
- 针对 PostMessage 消息丢失问题:
- 消息确认机制:在应用层实现消息确认机制,当目标窗口处理完消息后,向发送方反馈确认信息。若发送方长时间未收到确认,可重新发送消息。以下是简单示意代码(这里简化处理,实际需结合具体业务):
#include <windows.h>
#include <iostream>
#include <map>
std::map<UINT, bool> messageAck;
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
PSTR szCmdLine, int iCmdShow)
{
static TCHAR szAppName[] = TEXT("MessageTest");
HWND hwnd;
MSG msg;
WNDCLASS wndclass;
wndclass.style = CS_HREDRAW | CS_VREDRAW;
wndclass.lpfnWndProc = WndProc;
wndclass.cbClsExtra = 0;
wndclass.cbWndExtra = 0;
wndclass.hInstance = hInstance;
wndclass.hIcon = LoadIcon(NULL, IDI_APPLICATION);
wndclass.hCursor = LoadCursor(NULL, IDC_ARROW);
wndclass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
wndclass.lpszMenuName = NULL;
wndclass.lpszClassName = szAppName;
if (!RegisterClass(&wndclass))
{
MessageBox(NULL, TEXT("This program requires Windows NT!"),
szAppName, MB_ICONERROR);
return 0;
}
hwnd = CreateWindow(szAppName, TEXT("PostMessage Test"),
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, CW_USEDEFAULT,
CW_USEDEFAULT, CW_USEDEFAULT,
NULL, NULL, hInstance, NULL);
ShowWindow(hwnd, iCmdShow);
UpdateWindow(hwnd);
UINT customMsg = WM_USER + 1;
messageAck[customMsg] = false;
PostMessage(hwnd, customMsg, 0, 0);
// 模拟等待确认
while (!messageAck[customMsg])
{
// 可设置超时逻辑
}
while (GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return msg.wParam;
}
LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message)
{
case WM_USER + 1:
// 处理自定义消息
std::cout << "Received custom message in WndProc" << std::endl;
messageAck[WM_USER + 1] = true;
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hwnd, message, wParam, lParam);
}
return 0;
}