Mutex lock in C++ destructor causes exception when exit() called in Python

I have an application that loads a DLL with a class that handles jobs in a queue. In order to keep it thread safe, a mutex is locked whenever the queue is modified. When the application exits and the destructor is called, the mutex is locked in order to clear the queue.

However, when I load this DLL in Python, create an instance of the object, and call exit() (in Python) an exception is thrown when the mutex tries to lock:

Microsoft Visual Studio C Runtime Library has detected a fatal error in python.exe.

I have simplified the destructor down to just creating a mutex locally and trying to lock it, and can still reproduce the issue:

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();
}

If I take my unmodified code and simply remove the lock around the queue operation, it works fine.

Here is the seemingly relevant section of the call stack:

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

Questions:

  • If this code works when I exit my app normally (close the GUI), why would it be different when I exit() from Pyton?
  • Is there a "more correct" way to exit from Python?
  • Could this be related to the type of mutex/lock being used?
  • Do I even need to lock the section with the queue operations in my destructor? Or is it okay to delete the objects in the queue without a lock?
  • Edit: MCVE: QueueHandlerApp - Run the app or run script.py to demonstrate the issue.


    Some people, when confronted with a problem, think, "I know, I'll use lazy initialization." Now they have two problems.

    This is a bug in MSVC implementation of std::mutex . Before MSVC14 std::mutex and std::condition_variable would perform some internal initializations lazily. This alone is bad, but becomes even worse due to how modules are deinitialized on Windows.

    The bug was fixed in MSVC14 (Visual Studio 2015) - std::mutex was rewritten to use SRWLock internally. SRWLock is a simple primitive without additional dependencies. It relies only on atomic instructions and Keyed Events syscalls. As the kernel is isolated from the userspace, SRWLock 's should work seemlessly regardless of where they are used.

    Seems like you are using MSVC12 (Visual Studio 2013). You should switch to MSVC14 (Visual Studio 2015) or use Boost.Thread instead.

    There are actually many issues with std::mutex on MSVC12 and earlier. Some are related to the actual implementation used in CRT, others (as I heard) are caused by bugs in Windows 7 and were fixed in Windows 8.

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

    上一篇: System.Environment.Exit(0)阻止hockeyapp注册崩溃

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