Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/windows/15.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
为什么win32消息循环在线程化时停止工作? 我试图创建一个Win32 C++程序,在这个程序中,我必须同时处理消息并运行while循环。为了做到这一点,我想使用线程_C++_Windows_Multithreading_Winapi_Message Loop - Fatal编程技术网

为什么win32消息循环在线程化时停止工作? 我试图创建一个Win32 C++程序,在这个程序中,我必须同时处理消息并运行while循环。为了做到这一点,我想使用线程

为什么win32消息循环在线程化时停止工作? 我试图创建一个Win32 C++程序,在这个程序中,我必须同时处理消息并运行while循环。为了做到这一点,我想使用线程,c++,windows,multithreading,winapi,message-loop,C++,Windows,Multithreading,Winapi,Message Loop,当我将消息循环移动到从函数WinMain调用的单独过程中时,一切都正常工作。然而,当我使用下面的代码来执行该过程时,而不是简单地从主进程调用它,窗口将变得无响应 你知道为什么会这样吗 在WinMain内部,创建主窗口后,我删除了消息循环和返回值,添加了以下代码: std::thread t1(message_loop); t1.join(); return return_val; return_val是一个全局变量,我将使用它来接收消息循环结束时WinMain应返回的值 此外,功能信息_循环如

当我将消息循环移动到从函数WinMain调用的单独过程中时,一切都正常工作。然而,当我使用下面的代码来执行该过程时,而不是简单地从主进程调用它,窗口将变得无响应

你知道为什么会这样吗

在WinMain内部,创建主窗口后,我删除了消息循环和返回值,添加了以下代码:

std::thread t1(message_loop);
t1.join();
return return_val;
return_val是一个全局变量,我将使用它来接收消息循环结束时WinMain应返回的值

此外,功能信息_循环如下所示:

void message_loop()
{
    MSG messages;
    while (GetMessage (&messages, NULL, 0, 0))
    {
        /* Translate virtual-key messages into character messages */
        TranslateMessage(&messages);
        /* Send message to WindowProcedure */
        DispatchMessage(&messages);
    }
    return_val = messages.wParam;
}

根本原因是Windows具有线程消息队列的概念。每个线程都有自己的消息队列。在线程中运行GetMessage是可以的,但它只会获取属于该线程的消息,例如在该线程中创建的windows。无论其他线程是如何创建的,属于该线程的消息在线程中都不可见

正如您所说,只有在创建主窗口之后,才会创建std::thread。这意味着您有两个线程消息队列;一个来自创建主窗口的主线程,另一个来自std::thread的队列。后一个队列将保持为空

在GetMessage的第二个参数中可以看到这一点,传递HWND=0表示该线程的所有消息


理论上,可以为多个窗口使用多个线程,但这很快就会变得非常复杂。因此,在实践中,最常见的解决方案是使用主线程,唯一合理的选择是使用一个专用线程。

根本原因是Windows具有线程消息队列的概念。每个线程都有自己的消息队列。在线程中运行GetMessage是可以的,但它只会获取属于该线程的消息,例如在该线程中创建的windows。无论其他线程是如何创建的,属于该线程的消息在线程中都不可见

正如您所说,只有在创建主窗口之后,才会创建std::thread。这意味着您有两个线程消息队列;一个来自创建主窗口的主线程,另一个来自std::thread的队列。后一个队列将保持为空

在GetMessage的第二个参数中可以看到这一点,传递HWND=0表示该线程的所有消息


理论上,可以为多个窗口使用多个线程,但这很快就会变得非常复杂。因此,在实践中,最常见的解决方案是使用主线程,唯一合理的替代方案是使用一个专用线程。

一般来说,将UI创建代码和UI事件代码分离到单独的线程中不会很好。只需使用一个线程进行所有UI创建、修改和事件处理。如果您需要工作线程执行某些处理,则只要它们仅在处理,即不以任何方式使用UI,就可以执行此操作。从本质上看,windows仅在创建了windows的线程中创建事件队列,而这些队列仅处理由该线程创建的窗口的事件。在您的例子中,主线程创建了一个窗口,而您在另一个线程中创建了事件循环,因此它不会看到主线程创建的窗口的事件。这就是为什么windows程序通常在主线程中创建窗口,在主线程中设置事件循环,而其他线程不直接与GUI交互的原因。@Peter:这会错过PostThreadMessage。并非所有消息都与HWND关联。因此,Windows还需要在没有Windows的线程中创建线程消息队列。相关,因为PostThreadMessage是向此类后台线程发送消息的正常函数。请注意,进程中的初始线程是没有消息队列的基本NT线程,因此使用PostThreadMessageW向其发送消息失败,错误代码为error\u INVALID\u thread\u ID。当进程加载user32.dll时,它连接到一个窗口站和桌面,通常为WinSta0\Default,其内核进程和线程结构得到扩展以与桌面环境交互,这包括向进程中的每个线程添加消息队列。@MSalters-我之前的评论是针对一个问题,即为什么工作线程不能处理发送到主线程创建的窗口的事件。但是,是的,还有其他方法可以将事件发布到线程的事件队列中。一般来说,将UI创建代码和UI事件代码分离到单独的线程中不会很好地工作。只需使用一个线程进行所有UI创建、修改和事件处理。如果您需要辅助线程来执行某些处理,那么它们
只要它们只处理,即不以任何方式使用UI,就可以这样做。从本质上看,windows只在创建了windows的线程中创建事件队列,而这些队列只处理该线程创建的窗口的事件。在您的例子中,主线程创建了一个窗口,而您在另一个线程中创建了事件循环,因此它不会看到主线程创建的窗口的事件。这就是为什么windows程序通常在主线程中创建窗口,在主线程中设置事件循环,而其他线程不直接与GUI交互的原因。@Peter:这会错过PostThreadMessage。并非所有消息都与HWND关联。因此,Windows还需要在没有Windows的线程中创建线程消息队列。相关,因为PostThreadMessage是向此类后台线程发送消息的正常函数。请注意,进程中的初始线程是没有消息队列的基本NT线程,因此使用PostThreadMessageW向其发送消息失败,错误代码为error\u INVALID\u thread\u ID。当进程加载user32.dll时,它连接到一个窗口站和桌面,通常为WinSta0\Default,其内核进程和线程结构得到扩展以与桌面环境交互,这包括向进程中的每个线程添加消息队列。@MSalters-我之前的评论是针对一个问题,即为什么工作线程不能处理发送到主线程创建的窗口的事件。但是,是的,还有其他方法可以将事件发布到线程的事件队列中。在std::thread上运行GetMessage是可以的,如果并且仅当您也在同一个std::thread上调用CreateWindow时——不是真的。不需要窗口。GetMessage还通过PostThreadMessage处理线程消息。调用线程中的任何USER32函数,包括GetMessage,都会自动为该线程创建一个消息队列。目前真正的问题是窗口具有线程关联性,只有创建窗口的线程才能检索该窗口的消息。这可能就是你想要描述的。@RemyLebeau:线程亲和性比消息处理强一点,IMHO。线程关联还意味着许多在HWND上工作的函数只能从创建者线程调用。例如,GetDC通常被调用以响应WM_PAINT,但它也必须从接收WM_PAINT的同一线程调用。至于PostThreadMessage,我甚至在一条更新了该部分的注释中注意到了同样的情况。在std::thread上运行GetMessage是可以的,如果并且仅当您也在同一个std::thread上调用CreateWindow时——不是真的。不需要窗口。GetMessage还通过PostThreadMessage处理线程消息。调用线程中的任何USER32函数,包括GetMessage,都会自动为该线程创建一个消息队列。目前真正的问题是窗口具有线程关联性,只有创建窗口的线程才能检索该窗口的消息。这可能就是你想要描述的。@RemyLebeau:线程亲和性比消息处理强一点,IMHO。线程关联还意味着许多在HWND上工作的函数只能从创建者线程调用。例如,GetDC通常被调用以响应WM_PAINT,但它也必须从接收WM_PAINT的同一线程调用。至于PostThreadMessage,我甚至在更新的评论中也注意到了这一点。