Win7下静态变量析构导致进程卡死无法退出问题解决

项目中在用户机器Win7系统上好几次出现进程卡死,无法退出,在用户机器上抓取了dump,发现是在DllMain函数中执行了静态变量的析构,这个静态变量析构的时候会使用std::condition_variable 类型的成员变量通知其他线程退出。同时本地在win10机器上并不会出现。

最开始一直没查到原因,解决方法是在main函数退出之前就把静态变量反初始化函数执行,这样在DllMain中就只是一个空的析构函数,不会导致卡死了。

卡死dump截图:

当时我给的建议是,尽量不要在DllMain中执行很多同步逻辑,因为官方的最佳实践文档中给了出的建议也是这样:

https://docs.microsoft.com/en-us/windows/win32/dlls/dynamic-link-library-best-practices

第三条很明确的说了,不要和其他线程做同步的事情。

(备注:第一条曾经也遇到过这类死锁的dump,调用com组件的时候有时候会加载动态库,从而导致死锁。关键字:Loader Lock) 

一年之后又遇到了一个无法退出的case,我给用户远程并抓取了dump,发现还是类似的问题,只不过代码是在另外一个地方。

上次是我同事发现的这个问题,想办法绕过去了,这次我想弄明白原因,在网上查了一些资料,google查找的关键字:ZwReleaseKeyedEvent deadlock,因为堆栈最后一个函数是这个。

发现了很有价值的两篇文章:

第一篇:

https://stackoverflow.com/questions/60452341/stdconditional-variable-notify-problem-on-windows-7-called-from-destructor-oz​​​​​​​z​​​​​​​f

这篇文章这个人也遇到了,代码和我们的代码几乎一样:

class SomeObject
{
public:
    ~SomeObject()
    {
        StopThreadAndWait();
    }
    
    void StopThreadAndWait()
    {
            /* some logic  */
            m_stop = true;
            m_procesTasks.notify_one(); // <- the problem is here
            
            if (m_thread.joinable())
                m_thread.join();
    }
    
private:
    ...
    bool        m_stop;
    std::mutex  m_workQueueSync;
    
    std::thread m_thread;
    std::condition_variable m_procesTasks;
};

第二篇:

https://bugzilla.mozilla.org/show_bug.cgi?id=970063 

也就是说mozilla也遇到过这个问题,并且还给出了问题的答案,答案之一就是安装补丁,因为这个是windows系统的bug:

 

 补丁链接:

A process that is being terminated stops responding in Windows 7 or in Windows Server 2008 R2 - Microsoft Support

上面说明了只在win7 和 Windows Server 2008 R2 系统上会出现此问题。

到此,整个问题已经查明原因了。

但是,用户那里环境我们几乎是不能改变的,比如给用户安装这个补丁似乎成本很大。所以我们 就修改我们自己的代码,不要在DllMain中因为析构静态变量,执行了 std::condition_variable::notify_one(all)之类的函数,放到main函数退出之前执行即可。

第一篇文章中使用boost库中的condition_variable类也可以解决。同时我也把我发现的这个问题写在了这篇文章的评论中了。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值