• SetwindowText 之线程阻塞


    示意代码:

    CriticalSection g_Section;
    CDialog g_Dlg;

    // 工作线程函数
    UINT TreadFunc_A(PVOID para)
    {
    Sleep(10);

    g_Section.Lock();

    Sleep(3000);
    g_Dlg.m_Show_Edit.SetWindowText("TreadFuncA");
    // Beep(400,20);

    g_Section.Unlock();
    }

    // 窗口按钮消息函数
    void CDialog::OnButton1()
    {
    g_Section.Lock();

    g_Dlg.m_Show_Edit.SetWindowText("OnButton1");
    // Beep(800,20);
    g_Section.Unlock();
    }

    死锁出现条件:
    TreadFunc_A 进入 g_Section.Lock() 临界区
    在没有释放临界锁之前OnButton1()触发,g_Section.Lock() 阻塞等待
    ....永远都等不到了!

    实验:
    如果把g_Dlg.m_Show_Edit.SetWindowText替换成Beep,测滴答滴答的运行OK,不会出现死锁。
    看来问题出在SetWindowText上了。

    分析:
    导致死锁的一个隐含机制:SetWindowText 的实现使用了 SendMessage(WM_SETTEXT,...)
    而SendMessage是阻塞调用,等待窗口处理函数完成才返回。同时OnButton1也是窗口消息处理函数的回调映射,
    所以 g_Dlg.m_Show_Edit.SetWindowText("TreadFuncA"),在等待窗口消息处理函数的返回,线程被阻塞。
    而OnButton1占用了窗口消息函数执行,申请临界锁被阻塞。这样工作线程TreadFunc_A 占用临界锁同时等
    待窗口消息处理函数的返回,而界面线程占用窗口消息处理函数同时等待临界锁,于是就永远死翘翘的等下去了。

    结束语:
    MFC下面厚厚的封装,鬼才知道是什么实现机制。为了吃块糖,只需要剥开糖纸即可,为什么还要了解糖的加工工艺。
    吃别人的东西,直管往嘴里放就得了,出了问题再想办法,也只能这么着了。

    扩展阅读:

    1)Windows 窗口消息原理 

    2)SendMessage的实现机制

    3)MFC 消息映射框架

  • 相关阅读:
    Hibernate
    Redis的学习
    Redis的人门以及使用
    Win32 配置文件用法
    Using virtual lists
    windows log
    Win查询注册表获取CPU与内存参数
    MFC 多线程及线程同步
    使用Custom Draw优雅的实现ListCtrl的重绘
    MFC工具栏设计
  • 原文地址:https://www.cnblogs.com/Esperanto/p/3227478.html
Copyright © 2020-2023  润新知