我有一个使用_beginthreadex
生成大约20个线程的应用程序。所有线程都在等待队列填充,这是std::queue
:class MyQueue
上的包装。queue
被创建为全局变量,如MyQueue processQueue
< / p>
front
的{{1}}功能类似于
MyQueue
推送看起来像:
std::unique_lock<std::mutex> mlock(mutex_);
while (queue_.empty())
{
cond_.wait(mlock);
}
auto item = queue_.front();
queue_.pop();
return item;
std::unique_lock<std::mutex> mlock(mutex_);
queue_.push(item);
mlock.unlock();
cond_.notify_one();
是cond_,queue_ and mutex_
的成员变量。
所以最初,所有线程都处于等待状态。当MyQueue
有一个项目时,其中一个线程会读取并处理它。
应用程序关闭时,优雅或突然发生问题。 queue
发生了崩溃。
崩溃转储中的整个堆栈
msvcr120!Concurrency::details::_Condition_variable::notify_all
我尝试的事情,
ntdll!TppRaiseInvalidParameter+0x48
ntdll!TpAllocWait+0x6725f
kernel32!CreateThreadpoolWaitStub+0x1a
msvcr120!Concurrency::details::ExternalContextBase::PrepareForUse+0xa1
msvcr120!Concurrency::details::ExternalContextBase::ExternalContextBase+0xa2
msvcr120!Concurrency::details::SchedulerBase::AttachExternalContext+0xcf
Concurrency::details::SchedulerBase::CreateContextFromDefaultScheduler+0xfe
msvcr120!Concurrency::details::SchedulerBase::CurrentContext+0x26
msvcr120!Concurrency::critical_section::scoped_lock::scoped_lock+0x47
msvcr120!Concurrency::details::_Condition_variable::notify_all+0x23
msvcp120!_Cnd_destroy+0x1b
myfunction+0x36c501
msvcr120!doexit+0x145
msvcr120!__CRTDLL_INIT+0xce
ntdll!LdrpCallInitRoutine+0x41
ntdll!LdrShutdownProcess+0x142
ntdll!RtlExitUserProcess+0x78
KERNELBASE!DefaultHandler+0xf
KERNELBASE!CtrlRoutine+0x9b
kernel32!BaseThreadInitThunk+0xd
ntdll!RtlUserThreadStart+0x1d`
作为条件变量,但它没有解决问题。 std::unique_ptr
中调用_endthreadex(0)。这修复了退出时的崩溃,但我不认为这是正确的方法,因为我不确定哪个线程正在关闭。任何帮助都将受到高度赞赏。
答案 0 :(得分:1)
这是crt bug。崩溃,因为std::condition_variable
析构函数从DLL_PROCESS_DETACH
调用。
MyQueue queue
被创建为全局变量,而cond_
是。{ 成员变量MyQueue
因为cond_
是DLL中的全局对象 - 它在DLL_PROCESS_DETACH
上调用析构函数
从堆栈跟踪清除可见所有都从_Cnd_destroy
开始(从条件变量的析构函数调用)。 crt内部呼叫CreateThreadpoolWait
。致电TpAllocWait
。在这个api的最开始,存在下一行代码:
if (RtlGetCurrentPeb()->Ldr->ShutdownInProgress) TppRaiseInvalidParameter();
因为在调用ExitProcess
之后调用CreateThreadpoolWait
(查看堆栈跟踪ntdll!RtlExitUserProcess
)(在DLL_PROCESS_DETACH
处理程序中) - ShutdownInProgress
已经true
结果TppRaiseInvalidParameter
被调用 - 从堆栈跟踪中再次清晰可见。
此处 - std::condition_variable destructor crashes on VS2012此次崩溃的另一个例子。 - 如果你想看看崩溃的痕迹 - 你可以看到它绝对相同(突出显示堆栈中的主要点)
ntdll.dll!_NtRaiseException@12
ntdll.dll!_KiUserExceptionDispatcher@8
ntdll.dll!_TpAllocWait@16
kernel32.dll!_CreateThreadpoolWait@12
msvcp110d.dll!_Cnd_destroy(_Cnd_internal_imp_t * * cond) Line 35 C++
ConnectModelUtil.dll!std::condition_variable::~condition_variable() Line 41 C++
ConnectModelUtil.dll!_CRT_INIT(void * hDllHandle, unsigned long dwReason, void * lpreserved) Line 416 C
ConnectModelUtil.dll!__DllMainCRTStartup(void * hDllHandle, unsigned long dwReason, void * lpreserved) Line 522 C
所以这里只有解决方案 - 不要在dll中使用全局condition_variable
对象 - 否则你会在DLL_PROCESS_DETACH
上崩溃
也来自std::condition_variable::~condition_variable
程序员必须确保没有线程试图等待* this 一旦析构函数启动了
但在你的情况下并非如此。在等待条件变量cond_.wait(mlock);
期间,您的线程终止。所以从条件变量视图 - 线程仍然在等待 - 它连接到条件变量的数据(从它堆栈分配的块指针)。你需要或以某种方式在ExitProcess
调用之前等待所有线程 - 但你不能从此后调用的DLL_PROCESS_DETACH
执行此操作 - 因为此exe必须先调用一些dll函数。或者不使用等待全局条件变量
答案 1 :(得分:0)
你必须要等待关机。你班级析构函数中的cond_.notify_all()
可以解决你的问题吗?
答案 2 :(得分:0)
使用vc140使用visual studio 2015编译代码并且没有更多崩溃。毕竟看起来像visual studio 2013 bug。