Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/145.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ User32当消息泵处于空闲状态时发送消息挂起_C++_Multithreading_Winapi_Fibers - Fatal编程技术网

C++ User32当消息泵处于空闲状态时发送消息挂起

C++ User32当消息泵处于空闲状态时发送消息挂起,c++,multithreading,winapi,fibers,C++,Multithreading,Winapi,Fibers,我有一个用于第三方应用程序的多线程dll。My dll通过使用自定义消息类型调用SendMessage,在主UI线程上调用消息: typedef void (*CallbackFunctionType)(); DWORD _wm; HANDLE _hwnd; DWORD threadId; Initialize() { _wm = RegisterWindowMessage("MyInvokeMessage"); WNDCLASS wndclass = {0}; wnd

我有一个用于第三方应用程序的多线程dll。My dll通过使用自定义消息类型调用SendMessage,在主UI线程上调用消息:

typedef void (*CallbackFunctionType)();
DWORD _wm;
HANDLE _hwnd;
DWORD threadId;

Initialize()
{
    _wm = RegisterWindowMessage("MyInvokeMessage");
    WNDCLASS wndclass = {0};
    wndclass.hInstance = (HINSTANCE)&__ImageBase;
    wndclass.lpfnWndProc = wndProcedure;
    wndclass.lpszClassName = "MessageOnlyWindow";
    RegisterClass(&wndclass);
    _hwnd = CreateWindow(
         "MessageOnlyWindow",
         NULL,
         NULL,
         CW_USEDEFAULT,
         CW_USEDEFAULT,
         CW_USEDEFAULT,
         CW_USEDEFAULT,
         NULL,
         NULL,
         (HINSTANCE)&__ImageBase,
         NULL);
    threadId = GetCurrentThreadId();
}

void InvokeSync(CallbackFunctionType funcPtr)
{
    if (_hwnd != NULL && threadId != GetCurrentThreadId())
        SendMessage(_hwnd, _wm, 0, (LPARAM)funcPtr);
    else
        funcPtr();
}
static LRESULT CALLBACK wndProcedure(
    HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam)
{
    if (Msg == _wm)
    {
        CallbackFunctionType funcPtr = (CallbackFunctionType)lParam;
        (*funcPtr)();
    }
    return DefWindowProc(hWnd, Msg, wParam, lParam);
}
应用程序是MDI,我在后台执行打开文档/提取内容/处理/保存一堆文档,因此它不断切换活动文档并打开和关闭新文档

我的问题是,当处理试图使用上面的InvokeSync()函数调用主线程上的消息时,有时会遇到阻塞

当我在调试器中暂停它时,我看到主线程具有以下调用堆栈:

user32.dll!_NtUserGetMessage@16() + 0x15 bytes
user32.dll!_NtUserGetMessage@16() + 0x15 bytes
mfc42.dll!CWinThread::PumpMessage() + 0x16 bytes
// the rest is normal application stuff
被锁定的后台线程有如下调用堆栈:

user32.dll!_NtUserMessageCall@28() + 0x15 bytes
user32.dll!_NtUserMessageCall@28() + 0x15 bytes
mydll!InvokeSync(funcPtr)
// the rest is expected dll stuff
因此,它似乎被“SendMessage()”调用卡住了,但就我所见,主线程上的消息泵处于空闲状态

但是,如果我手动单击一个非活动文档(使其处于活动状态),不知何故这会唤醒所有内容,SendMessage()事件最终会通过,并恢复处理

主应用程序使用Microsoft光纤,每个文档1根光纤。我的SendMessage会不会被卡在背景光纤中而被切断了?在光纤处于非活动状态或其他状态之前,只有通过强制上下文切换,该光纤才能处理其消息?我真的不明白线和纤维是如何相互作用的,所以我有点抓紧稻草


是什么原因导致邮件如此未经处理?更重要的是,有没有办法防止这种情况发生?或者至少,我该如何调试这种情况?

我实现了我自己的消息队列,以及一种消息格式,它使用信号量通知消息何时收到,以及消息何时完成,然后每1秒重复一次PostMessage,直到“message received”收到信号为止,然后等待“消息完成”,无限超时

任何额外的postmessage都会被忽略,因为它们不再包含要执行的有效负载,它们只是告诉主线程检查队列中的传入事件


自从我做了这些更改后,我就再也没有遇到这种情况了。据我所知,发送的消息必须在断开光纤的队列中结束,并被遗忘,直到该光纤再次接通。通过重新发送消息,它可以一直重试,直到活动光纤注意到消息在那里。

检查arguments to
GetMessage
。第三个和第四个是消息ID范围。如果消息的ID超出此范围,您的消息将很高兴地位于队列中。

最有可能的情况是,您将消息发送到一个由线程拥有的窗口,而该窗口没有消息泵否,我发布了拥有HWND的线程的调用堆栈,它在那里等待g on _NtUserGetMessage()。可能会正确处理9999/10000条消息,只是偶尔会有一条消息挂在那里,被遗忘,等待处理。根据您的描述,消息从未到达队列。有时这可能是一种误导症状(表示正在发生未正确报告的其他事件)。您的输出窗口是否显示任何值得注意的项目?仅显示一组消息“线程'Win32 thread'(0x???)已退出,代码为0(0x0)。“SendMessage()可能会导致死锁。请改用PostMessage()。建议不错,但GetMessage在mfc42.dll PumpMessage中。”(),并且它确实是在光纤上下文切换之后交付的,所以我认为范围过滤不太可能是原因。