小议避免进程退出时的死锁

——Windows GUI程序中使用线程的心得体会

 ①避免在工作者线程中使用SendMessage,改用PostMessage比较好。

原因是这样的,以一个普通程序退出为例,我们经常会使用以下方式构建退出逻辑:

主线程正在消息处理函数

工作者线程正在处理任务

void OnDestroy(){//WM_DESTROY
  //1发送退出消息或命令给工作者线程:
  SetEvent(m_hStop);
  //2等待线程退出:
  WaitForSingleObject(m_hThread, INFINITE);
// DebugPoint;
  m_hThread=NULL;
  //3销毁窗口资源
  CWnd::OnDestroy();
}

void DoWork(){
  char strTitle[100]={0};
  while(WAIT_OBJECT_0 != WaitForSingleObject(m_hStop, 0)){
    Sleep(5000);//模拟工作线程的任务处理
    //访问界面资源:
    SendMessage(m_hMainWnd, WM_GETTEXT, sizeof(strTile) , strTitle);
//DebugPoint;
    Sleep(0);
  }
  CloseHandle(m_hThread);
}

如上所示,只要主线程开始处理WM_DESTROY消息后,只有等到OnDestroy返回,主线程才会处理下一个Windows消息。一旦OnDestroy函数开始执行且还没有返回,DoWork中发出的WM_GETTEXT消息就不会被主线程处理,使用SendMessage后工作者线程就会等待主线程处理WM_GETTEXT进入休眠,注意这种休眠无法使用ResumeThread唤醒(即使唤醒只要主线程没有处理WM_GETTEXT消息也会继续睡过去)。而这时OnDestroy函数正在用WaitForSingleObject等待DoWork检测m_hStop信号退出线程,所以两者互相等待都进入了休眠,这样就产生了死锁。

很多朋友一定会说,那就把OnDestroyWaitForSingleObject去掉直接往后执行不就没有死锁了么?死锁是没有了,由于OnDestroy函数的主要职责就是负责释放资源,接下来它一定会调用类似CWnd::OnDestroy()函数来销毁窗口资源,这样一来DoWork里就很有可能因为访问界面资源而崩溃。

所以,②应该避免在工作者线程中直接访问界面资源,包括不要使用GetWindowsText等函数。可以把要显示到界面上的数据,放进一个自己构建的队列中,然后使用PostMessage发出特定的消息或者用户自定义的消息,由消息处理函数去完成。

③如果必须在线程里访问界面资源怎么办?可以使用类似MFC中的界面线程。

下面是我在工作者线程里直接访问界面资源的方法,利用消息泵:

工作者线程正在处理任务

void DoWork(){
  char strTitle[100]={0};
  MSG sMsg={0};
  while(WAIT_OBJECT_0 != WaitForSingleObject(m_hStop, 0)){
    Sleep(5000);//模拟工作线程的任务处理
    //到消息队列里取出关注的消息WM_DESTROY
    if(PeekMessage(&sMsg, m_hMainWnd, WM_DESTROY, WM_DESTROY, PM_NOREMOVE)){
      break;
    }
    //尽快访问界面资源,这里还是有可能死锁的,最好不要在这中间插入指令。
    SendMessage(m_hMainWnd, WM_GETTEXT, sizeof(strTile) , strTitle);
//DebugPoint;
    Sleep(0);
  }
  //退出线程前释放相应资源:
  CloseHandle(m_hThread);
} 

 

上面也许不是解决退出死锁的万能方法,只是我的一点心得,希望大家有更好的办法也贴上来。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

dj0379

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值