【发布时间】:2017-11-17 05:26:22
【问题描述】:
我有一个应用程序加载一个带有一个类的 DLL,该类处理队列中的作业。为了保证线程安全,只要队列被修改,互斥锁就会被锁定。当应用程序退出并调用析构函数时,互斥锁被锁定以清除队列。
但是,当我在 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 来演示问题。
【问题讨论】:
-
在析构函数中加锁是绝对不行的。
-
@CaptainObvlious,所以您是说互斥对象在被锁定时被销毁?如果我不应该在析构函数中使用锁,那么我应该在没有锁的情况下清理队列吗?还是有其他清理队列的方法?
-
您在析构函数中创建了一个全新的锁,然后您将其锁定并解锁。这到底应该达到什么目的(这很有用)?
-
@SFBA26 那么也许您应该发布minimal reproducible example 以便我们有机会帮助您解决问题。仅仅发布不做任何事情并且我们无法编译/运行/测试的代码 sn-ps 是相当没用的。
-
@NeilButterworth 锁定析构函数没有错。这是
operator delete已经做的事情。任何第三方分配器也需要这个。这里的问题是std::mutex实现损坏,由于 Windows 上的模块取消初始化损坏,情况变得更糟。
标签: python c++ multithreading locking mutex