在Python中调用exit()时,C ++析构函数中的互斥锁会导致异常

我有一个应用程序加载了一个处理队列中作业的类。 为了保持线程安全,只要队列被修改,就会锁定互斥锁。 当应用程序退出并且调用析构函数时,互斥锁被锁定以清除队列。

然而,当我在Python中加载这个DLL时,创建一个对象的实例,并调用exit() (在Python中),当互斥锁试图锁定时会引发异常:

Microsoft Visual Studio C运行时库已在python.exe中检测到致命错误。

我已经简化了析构函数,直到在本地创建一个互斥锁并尝试锁定它,并且仍然可以重现该问题:

QueueHandler::~QueueHandler(void)
{
    mutex mut; // in reality, this is a member of the class and there are actual operations between lock and unlock
    mut.lock(); // exception here
    mut.unlock();
}

如果我使用未修改的代码,只需在队列操作周围删除锁定,它就可以正常工作。

这是调用堆栈看似相关的部分:

KernelBase.dll!RaiseException() Unknown
msvcr120.dll!_CxxThrowException(void * pExceptionObject, const _s__ThrowInfo * pThrowInfo) Line 154 C++
msvcr120.dll!Concurrency::details::SchedulerBase::SchedulerBase(const Concurrency::SchedulerPolicy & policy) Line 149   C++
msvcr120.dll!Concurrency::details:: SchedulerBase::CreateWithoutInitializing(const Concurrency::SchedulerPolicy & policy) Line 285  C++
msvcr120.dll!Concurrency::details:: SchedulerBase::CreateContextFromDefaultScheduler() Line 571 C++
msvcr120.dll!Concurrency::details::SchedulerBase::CurrentContext() Line 404 C++
[Inline Frame] msvcr120.dll!Concurrency::details::LockQueueNode::{ctor (unsigned int) Line 619  C++
msvcr120.dll!Concurrency::critical_section::lock() Line 1031    C++
msvcp120.dll!mtx_do_lock(_Mtx_internal_imp_t * * mtx, const xtime * target) Line 67 C++
--> MyApplication.dll!QueueHandler::~QueueHandler() Line 106    C++
MyApplication.dll!_CRT_INIT(void * hDllHandle, unsigned long dwReason, void * lpreserved) Line 416  C
MyApplication.dll!__DllMainCRTStartup(void * hDllHandle, unsigned long dwReason, void * lpreserved) Line 522    C
ntdll.dll!LdrShutdownProcess()  Unknown
ntdll.dll!RtlExitUserProcess()  Unknown
msvcr100.dll!doexit(int code, int quick, int retcaller) Line 621    C
python27.dll!000000001e13be65() Unknown
...
python27.dll!000000001e043494() Unknown
python.exe!000000001d00119e()   Unknown

问题:

  • 如果这段代码在我正常退出我的应用(关闭GUI)时起作用,为什么当我从Pyton exit()时会有所不同?
  • 是否有“更正确”的方式退出Python?
  • 这可能与正在使用的互斥/锁的类型有关吗?
  • 我甚至需要在析构函数中使用队列操作锁定该部分? 或者可以在不锁定的情况下删除队列中的对象吗?
  • 编辑: MCVE: QueueHandlerApp - 运行该应用程序或运行script.py来演示该问题。


    有些人遇到问题时会想:“我知道,我会用懒惰的初始化。” 现在他们有两个问题。

    这是std::mutex MSVC实现中的一个错误。 在MSVC14 std::mutexstd::condition_variable会懒惰地执行一些内部初始化。 这一点很糟糕,但由于Windows上的模块未初始化而变得更糟。

    该错误在MSVC14(Visual Studio 2015)中修复 - std::mutex被重写为SRWLock内部使用SRWLockSRWLock是一个简单的原语,没有额外的依赖关系。 它仅依赖于原子指令和键控事件系统调用。 由于内核与用户空间隔离, SRWLock无论在什么地方使用都应该可以SRWLock地工作。

    看起来像你正在使用MSVC12(Visual Studio 2013)。 您应该切换到MSVC14(Visual Studio 2015)或使用Boost.Thread。

    实际上MSVC12和更早版本的std::mutex存在很多问题。 有些与CRT中使用的实际实现有关,其他(如我所知)是由Windows 7中的错误引起的,并在Windows 8中得到修复。

    链接地址: http://www.djcxy.com/p/51235.html

    上一篇: Mutex lock in C++ destructor causes exception when exit() called in Python

    下一篇: Debugger gets stuck in WPF OnStartup method