有一个单文档的程序,响应一个菜单消息,用afxbeginthread创建了一个用户界面线程(这个线程是基于cwinthread的,在initlinstance()里面创建了一个对话框并显示出来),在这个对话框中响应一个按钮消息,进入一个while死循环,这个时候按照常理,单文档是主线程,对话框是一个后来创建的子线程,子线程进入死循环被阻塞,主线程没有进入任何函数是不应该被阻塞的,可以响应鼠标消息,但是实际情况是单文档不能响应鼠标消息,比如移动窗口,最大化等,也就是主线程也被阻塞了。     谁来解释一下这是怎么回事啊?如果是这样,多线程的意义何在?

解决方案 »

  1.   

    ....单文档(主线程)有它自己的消息循环,用户界面线程(不是工作线程)也有它自己的消息循环。
    在消息循环中有个:DispatchMessage函数,将消息发送给系统,并由系统去调用窗口过程中的消息处理函数。那么它的程序流是:DispatchMessage函数将控制权交给系统,系统调用消息处理函数(即系统又将控制权交给消息处理函数,等消息处理函数处理完成后,它又将控制权交还给系统,系统又交还给DispatchMessage函数,并进入下一次消息循环。
    对话框的按钮消息处理函数一直死循环,那么控制权一直都在消息处理函数中,系统处于等待控制权返回状态。而当主线程的消息循环的DispatchMessage函数将控制权交给系统时,因系统处于等到上次控制权返回的状态,它是无法再次获取新的控制权的,所以主线程的消息也得不到处理。
      

  2.   

    每个线程是有单独的消息队列的,一个线程阻塞了不会影响另一个的,会阻塞只能说明你的方法不对,刚才验证了一下,响应一个菜单命令创建一个新线程,然后新线程在处理ID_FILE_NEW菜单命令时死循环,死掉的只有新建窗口// CSDISampleApp message handlers
    #include <process.h>
    UINT WINAPI ThreadProc(LPVOID lpParam);
    void CSDISampleApp::OnTest()
    {
    // TODO: Add your command handler code here
    ::CloseHandle((HANDLE)::_beginthreadex(NULL, 0, ThreadProc, this, 0, NULL));
    }// Forward declarations of functions included in this code module:
    ATOM MyRegisterClass(HINSTANCE hInstance);
    BOOL InitInstance(HINSTANCE, int);
    LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
    INT_PTR CALLBACK About(HWND, UINT, WPARAM, LPARAM);UINT WINAPI ThreadProc(LPVOID lpParam)
    {
    // TODO: Place code here.
    MSG msg; // Initialize global strings
    HINSTANCE hInstance = ::GetModuleHandle(NULL);
    MyRegisterClass(hInstance);
    InitInstance(hInstance, SW_SHOW); // Main message loop:
    while (GetMessage(&msg, NULL, 0, 0))
    {
    TranslateMessage(&msg);
    DispatchMessage(&msg);
    } return (int) msg.wParam;
    }//
    //  FUNCTION: MyRegisterClass()
    //
    //  PURPOSE: Registers the window class.
    //
    //  COMMENTS:
    //
    //    This function and its usage are only necessary if you want this code
    //    to be compatible with Win32 systems prior to the 'RegisterClassEx'
    //    function that was added to Windows 95. It is important to call this function
    //    so that the application will get 'well formed' small icons associated
    //    with it.
    //
    ATOM MyRegisterClass(HINSTANCE hInstance)
    {
    WNDCLASSEX wcex; wcex.cbSize = sizeof(WNDCLASSEX); wcex.style = CS_HREDRAW | CS_VREDRAW;
    wcex.lpfnWndProc = WndProc;
    wcex.cbClsExtra = 0;
    wcex.cbWndExtra = 0;
    wcex.hInstance = hInstance;
    wcex.hIcon = NULL;
    wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
    wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
    wcex.lpszMenuName = MAKEINTRESOURCE(IDR_MAINFRAME);
    wcex.lpszClassName = _T("Test Class");
    wcex.hIconSm = NULL; return RegisterClassEx(&wcex);
    }//
    //   FUNCTION: InitInstance(HINSTANCE, int)
    //
    //   PURPOSE: Saves instance handle and creates main window
    //
    //   COMMENTS:
    //
    //        In this function, we save the instance handle in a global variable and
    //        create and display the main program window.
    //
    BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
    {
       HWND hWnd;   hWnd = CreateWindow(_T("Test Class"), _T("TEST"), WS_OVERLAPPEDWINDOW,
          CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, NULL, NULL, hInstance, NULL);   if (!hWnd)
       {
          return FALSE;
       }   ShowWindow(hWnd, nCmdShow);
       UpdateWindow(hWnd);   return TRUE;
    }//
    //  FUNCTION: WndProc(HWND, UINT, WPARAM, LPARAM)
    //
    //  PURPOSE:  Processes messages for the main window.
    //
    //  WM_COMMAND - process the application menu
    //  WM_PAINT - Paint the main window
    //  WM_DESTROY - post a quit message and return
    //
    //
    LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
    {
    int wmId, wmEvent;
    PAINTSTRUCT ps;
    HDC hdc; switch (message)
    {
    case WM_COMMAND:
    wmId    = LOWORD(wParam);
    wmEvent = HIWORD(wParam);
    // Parse the menu selections:
    switch (wmId)
    {
    case ID_FILE_NEW:
    while (TRUE);
    break;
    default:
    return DefWindowProc(hWnd, message, wParam, lParam);
    }
    break;
    case WM_PAINT:
    hdc = BeginPaint(hWnd, &ps);
    // TODO: Add any drawing code here...
    EndPaint(hWnd, &ps);
    break;
    case WM_DESTROY:
    PostQuitMessage(0);
    break;
    default:
    return DefWindowProc(hWnd, message, wParam, lParam);
    }
    return 0;
    }// Message handler for about box.
    INT_PTR CALLBACK About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
    {
    UNREFERENCED_PARAMETER(lParam);
    switch (message)
    {
    case WM_INITDIALOG:
    return (INT_PTR)TRUE; case WM_COMMAND:
    if (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL)
    {
    EndDialog(hDlg, LOWORD(wParam));
    return (INT_PTR)TRUE;
    }
    break;
    }
    return (INT_PTR)FALSE;
    }
      

  3.   

    ....在MFC消息机制下,我也不知道怎么做了!你可参考下#8楼的,用API函数来实现看看...
      

  4.   

    补充下:你试试在你的按钮消息处理函数中,在生成一个工作线程(work thread),由该工作线程去完成你的耗时的工作,不要在你的按钮消息处理函数中去完成耗时的的工作。