今天学习的时候看到了一个例子,通过子线程来设置CProgressCtrl的进度,其中有一个关于死锁的问题不太明白,代码大致如下:struct threadInfo
{
    UINT nMilliSecond;
    CProgressCtrl* pctrlProgress;
};void CMy1_18_1Dlg::OnStart() 
{
    // TODO: Add your control notification handler code here
    
    UpdateData(TRUE);
    Info.nMilliSecond=m_nMilliSecond;
    Info.pctrlProgress=&m_ctrlProgress;
    
    hThread=CreateThread(NULL,
        0,
        (LPTHREAD_START_ROUTINE)ThreadFunc,
        &Info,
        0,
        &ThreadID);
        
//         GetDlgItem(IDC_START)->EnableWindow(FALSE);
//         WaitForSingleObject(hThread,INFINITE);
//         GetDlgItem(IDC_START)->EnableWindow(TRUE);
    
}  //这个是“开始”按钮的响应函数,用它来启动一个线程,设置进度条
UINT ThreadFunc(LPVOID lpParam) {
    threadInfo* pInfo=(threadInfo*)lpParam;    for(int i=0;i<100;i++)
    {
        int nTemp=pInfo->nMilliSecond;
        
        pInfo->pctrlProgress->SetPos(i);
        
        Sleep(nTemp);
    }
    return 0;
}// 这个是线程函数不太明白的地方是OnStart函数中被注释掉的部分,资料上说如果不注释掉会导致死锁,试验的结果的确是会这样,为什么在子线程中设置进度条会死锁呢?难道这个过程还需要和主线程交互?

解决方案 »

  1.   

    关键是这句:
    // WaitForSingleObject(hThread,INFINITE);主线程等待子线程结束,子线程中调用pInfo->pctrlProgress->SetPos(i);来SendMessage发送PBM_SETPOS消息到UI主线程,子线程等待主线程处理该消息然后再返回,但是而这个时候主线程又在等待子线程结束,从而导致死锁发生。
      

  2.   

    如果要设置进度条控件,就一定要向主线程“发送”消息么?如果我在子线程中通过GetDlgItem获得一个和进度条控件关联的CProgressCtrl对象来设置不行么? 事实证明这样也不行,我只是不清楚为什么这样不行,呵呵,难道进度条只能由创建它的进程设置?(进度条控件应该是由主线程创建的把?)
      

  3.   

    一般强烈不建议在子线程中直接去操作界面控件,改用发送自定义消息到UI主线程,在UI主线程的自定义消息响应函数中去更新控件信息这种做法比较好。
      

  4.   


    系统窗口API本身就是通过SendMessage来实现的
    如SetWindowText,就是通过SendMessage WM_SETTEXT实现的
    而不是直接读取HWND对应的数据结构
      

  5.   

    不注释掉那几行,则主线程不会被调度,无法响应工作线程设置进度的消息,而SetPos()也就是SendMessage(PBM_SETPOS...)是个同步函数,就不会返回,于是就死在那里了。
      

  6.   

    // WaitForSingleObject(hThread,INFINITE);这个不是锁死,是主线程 剥夺了子线程的执行权
      

  7.   

    WaitForSingleObject(hThread,INFINITE);
    子线程无限期停止执行,直到 hThread状态改变为止。