C++11 使用std::mutex而不是boost::mutex时出现未处理的异常

C++11 使用std::mutex而不是boost::mutex时出现未处理的异常,c++11,mutex,openni,unhandled-exception,boost-mutex,C++11,Mutex,Openni,Unhandled Exception,Boost Mutex,我试图摆脱代码中的一些boost依赖项,而是使用新的C++11特性(Visual Studio 2013) 在我的一个组件中,我使用了boost::mutex和boost::lock\u-guard,一切正常。当我将std::mutex与std::lock\u guard一起使用时,从main()返回时会出现以下错误 Grabbertest.exe中0x7721E3BE(ntdll.dll)处未处理的异常:0xC0000005:访问冲突读取位置0xA6B491 实际项目相当复杂,因此很难提供完整

我试图摆脱代码中的一些boost依赖项,而是使用新的C++11特性(Visual Studio 2013)

在我的一个组件中,我使用了
boost::mutex
boost::lock\u-guard
,一切正常。当我将
std::mutex
std::lock\u guard
一起使用时,从
main()
返回时会出现以下错误

Grabbertest.exe中0x7721E3BE(ntdll.dll)处未处理的异常:0xC0000005:访问冲突读取位置0xA6B491

实际项目相当复杂,因此很难提供完整的工作代码示例来重现此问题。在我的实际项目中,互斥体在运行时加载的共享库中使用(但在我从
main()
返回时应该已经卸载了)

我的问题是:

  • boost::mutex
    std::mutex
    的设计行为是否完全相同
  • 如果没有,区别是什么?使用
    std::mutex
    而不是
    boost::mutex
    时,我需要记住什么
  • 在共享库中,我使用
    boost::thread
    框架创建线程。是否
    std::mutex
    只能与
    std::thread
    s一起使用,并且与
    boost::thread
    s不兼容
编辑: 我还注意到一件事:当我卸载动态加载的共享库时,这需要一些时间。(DLL访问硬件,需要一段时间才能完全关闭所有内容)。当我切换到
std::mutex
时,看起来DLL几乎可以立即卸载,但是当从
main()
返回时,程序会崩溃。我的印象是,
std::mutex
的问题特别是在DLL的上下文中

编辑2: 应用程序和DLL都是使用v120工具集在调试配置中新构建的,并且与运行库(/MTd)静态链接

编辑3: 在下面可以找到callstack。这个例外似乎来自司机的某个地方。只是出于偶然,我发现这与我使用的互斥实现有关

ntdll.dll!7721e3be()
[Frames below may be incorrect and/or missing, no symbols loaded for ntdll.dll]
ntdll.dll!7721e023()
kernel32.dll!76b014ad()
msvcr100.dll!71b0016a()
PS1080.dll!oniDriverDestroy() Line 29
OpenNI2.dll!oni::implementation::DeviceDriver::~DeviceDriver() Line 95
OpenNI2.dll!oni::implementation::Context::shutdown() Line 324
OpenNi2Grabber.dll!openni::OpenNI::shutdown() Line 2108
OpenNi2Grabber.dll!GrabberSingletonImpl::~GrabberSingletonImpl() Line 46
OpenNi2Grabber.dll!`GrabberSingletonImpl::getInstance'::`2'::`dynamic atexit destructor for 'inst''()
OpenNi2Grabber.dll!doexit(int code, int quick, int retcaller) Line 628
OpenNi2Grabber.dll!_cexit() Line 448
OpenNi2Grabber.dll!_CRT_INIT(void * hDllHandle, unsigned long dwReason, void * lpreserved) Line 169
OpenNi2Grabber.dll!__DllMainCRTStartup(void * hDllHandle, unsigned long dwReason, void * lpreserved) Line 399
OpenNi2Grabber.dll!_DllMainCRTStartup(void * hDllHandle, unsigned long dwReason, void * lpreserved) Line 340
ntdll.dll!7722b990()
ntdll.dll!77249bad()
ntdll.dll!77249a4f()
kernel32.dll!76b079ed()
GrabberTester.exe!__crtExitProcess(int status) Line 776
GrabberTester.exe!doexit(int code, int quick, int retcaller) Line 678
GrabberTester.exe!exit(int code) Line 417
GrabberTester.exe!__tmainCRTStartup() Line 264
GrabberTester.exe!mainCRTStartup() Line 165
kernel32.dll!76b0338a()
ntdll.dll!7722bf32()
ntdll.dll!7722bf05()
编辑4:
可能这是OpenNI2 SDK中的一个bug,只有在这些非常特定的条件下才能观察到。所以我在这个问题上添加了openni标签。但问题仍然存在:为什么它与
boost::mutex
一起工作,而与
std::mutex
不一起工作?

我添加了相同的问题,解决的是。。。一个完整的手动清理+重建!验证是否删除了所有.obj、.dll、.lib文件。

最可能的问题是静态初始化地狱,我最近经历了几乎相同的事情。下面是正在发生的情况:

  • 您有一个静态互斥体(可以是静态类的成员)
  • doexit()代码开始清理静态内容
  • 互斥锁在doexit()中的某个地方被销毁
  • 某些东西在被销毁后使用互斥锁,通常在析构函数中使用多次
  • 问题是你并不知道静态对象的破坏顺序。因此,如果你有:

    static std::mutex staticMutex;
    
    void someFunction()
    {
        std::unique_lock<std::mutex> lock(staticMutex);
        doSomethingAwesome();
    }
    
    然后,当调用~StaticObjA()时,您的静态互斥体就可以被删除/销毁/死掉。当对象在不同的编译单元中定义(即在不同的文件中定义)时,问题会更加严重

    我的解决建议是尽量减少对静态对象的依赖,您可以尝试使用一个静态对象来处理其他所有内容的构造/破坏,这样您就可以控制事件的顺序。或者干脆不要使用静态。

    不要使用Mircosoft的std::mutex(或递归\u mutex…)!!!! 我也有类似的问题。我正在使用VS2012

    如果在dll中使用std::mutex,则不能卸载此dll。因为你有一个未定义的行为。(在我的案例0xC0000005中:访问冲突读取位置…)。
    或者无法卸载dll。(may“?runtime?”递增加载计数器。Double FreeLibrary()卸载dll)

    当我的代码尝试两次锁定同一互斥体时,我遇到了类似的问题:一个函数获得了锁,然后调用另一个函数,该函数试图在同一全局/静态互斥体上获取锁

    mutex queueMutex;
    
    void f1()
    {
        lock_guard<mutex> guard(queueMutex);
        f2();
    }
    
    void f2()
    {
        lock_guard<mutex> guard(queueMutex); //unhandled exception!
    }
    
    mutex队列mutex;
    void f1()
    {
    锁定保护(队列互斥);
    f2();
    }
    无效f2()
    {
    lock_guard guard(queueMutex);//未处理的异常!
    }
    
    就我所知,stl和boost实现之间没有显著差异。我见过互斥锁这样做的唯一原因是当一个线程锁定而另一个线程试图解锁时。我会确保在所有可能的实例中都使用锁保护,并通过大量同步调试输出调查所有其他用途。我知道标准线程设施的一些VS2013实现在各个方面都存在缺陷。不知道互斥是否是其中的一部分。你有没有可能混合了不同的运行时版本?或者没有进行完整的重建?(即,某些对象文件、DLL等仍在使用旧代码)至少发布了崩溃的堆栈跟踪。“当对象在不同的编译单元中定义时,问题会更加严重。”除非在不同的编译单元中定义,否则问题甚至不应存在。单个翻译单元内的初始化顺序定义良好。另外,
    std::mutex
    的构造函数是constexpr,因此全局
    std::mutex
    应该在需要动态初始化的任何全局对象之前初始化,因此应该在这些对象之后销毁。我不认为微软的实现使用了
    constexpr
    ,因此不符合这一要求。我认为这只是一个糟糕的设计,而且与
    std::mutex
    没有问题。我同意你的看法,@andygue在这种情况下使用递归的\u mutex
    mutex queueMutex;
    
    void f1()
    {
        lock_guard<mutex> guard(queueMutex);
        f2();
    }
    
    void f2()
    {
        lock_guard<mutex> guard(queueMutex); //unhandled exception!
    }