-1

我想我正在陷入僵局,几个小时以来一直在寻找解决方案。有什么建议么?我想做的是:点击startGame按钮,创建向服务器发送请求然后得到答案的线程,在答案之后,线程必须向主进程发送一条消息以初始化游戏窗口......

属于 WinMain 的消息过程:

LRESULT CALLBACK WndProc(HWND myWindow, UINT messg, WPARAM wParam, LPARAM lParam)
   {
        switch (messg) {
               case WM_STARTGAME:
            DestroyWindow(hStartGameButton);
            DestroyWindow(hHistoryButton);

            InitGameWindow(myWindow);
        break;


                case WM_COMMAND:

                  switch(LOWORD(wParam))
                  {
                        case IDC_STARTGAME_BUTTON:
                        {
                          parametros param;
                          param.myWindow = myWindow;

                          start_game = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)ThreadStartGame, (LPVOID)&myWindow, 0, NULL);
                        }

                  }
   }

这是线程:

DWORD WINAPI ThreadStartGame(LPVOID param){
HWND w = (HWND)param;
DWORD n;
BOOL ret;
mensagem resposta;


mensagem msg;
msg.tipo = COMECAR_JOGO;
msg.verifica = true;

if (!WriteFile(hPipe, &msg, (DWORD)sizeof(mensagem), &n, NULL)) {return 0;}

    ret = ReadFile(hPipeN, &resposta, (DWORD)sizeof(mensagem), &n, NULL);
    if (!ret || !n) {
        return false;
     }

PostMessage(w, WM_STARTGAME, NULL, NULL); // <- THIS GETS EXECUTED BUT NOTHINK HAPPENS AFTER

return 0;
}
4

3 回答 3

3

我认为这里没有任何僵局。

start_game = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)ThreadStartGame, (LPVOID)&myWindow, 0, NULL);

此行将 HWND 的地址传递给线程 (&myWindow)

HWND w = (HWND)param;

此行使用地址本身作为 HWND,SendMessage 将消息发送到该地址,该地址不是 HWND。

尝试修改为

start_game = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)ThreadStartGame, (LPVOID)myWindow, 0, NULL);

于 2013-06-13T11:40:45.593 回答
2

即使不看代码,我也可以立即告诉您:不要SendMessage在线程之间使用。我推荐阅读Psychic debugging:诊断死锁的第一步很简单,就是跟着钱走防止 Windows 应用程序挂起

在您的 UI 线程中使用异步窗口消息 API,尤其是通过替换SendMessage它的非阻塞对等点之一PostMessage、、SendNotifyMessageSendMessageCallback

...任何跨越线程边界的阻塞调用都具有可能导致死锁的同步属性。调用线程执行具有“获取”语义的操作,并且在目标线程“释放”该调用之前无法解除阻塞。相当多的 User32 函数(例如SendMessage),以及许多阻塞 COM 调用都属于这一类。

于 2013-06-13T11:47:48.097 回答
1

首先,您不太可能一开始就这样做。引用MSDN

调用 C 运行时库 (CRT) 的可执行文件中的线程应使用 _beginthreadex 和 _endthreadex 函数进行线程管理,而不是 CreateThread 和 ExitThread;这需要使用 CRT 的多线程版本。如果使用 CreateThread 创建的线程调用 CRT,CRT 可能会在内存不足的情况下终止进程。

其次,您的线程可以是工作线程或 UI 线程,从第一种类型开始,您不能调用大多数与窗口相关的函数,因为它没有消息泵。DestroyWindow 就是这样。(很多次我都尝试使用 MessageBox,尽管我自己的评论在上面几行告诉它在该函数中是被禁止的;)。

在工作线程中,通常的方法是使用PostThreadMessageUI 线程并对其做出反应。(如果你有多个 UI 线程,我不知道规则,从来没有足够的勇气。)

于 2013-06-13T11:56:44.923 回答