在std :: condition_variable中调用后,由于INVALID PARAMETER导致应用程序崩溃 [英] Application crash due to INVALID PARAMETER after call in std::condition_variable
问题描述
我有一个使用_beginthreadex
生成大约20个线程的应用程序.所有线程都在等待填充的队列上,该队列是对std::queue
:class MyQueue
的包装.queue
被创建为全局变量,类似于MyQueue processQueue
I have an application that spawns some 20 threads using _beginthreadex
. All of the threads are waiting on a queue to be filled which is a wrapper over the std::queue
: class MyQueue
.The queue
is created as a global variable something like MyQueue processQueue
MyQueue
的front
功能类似于
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
崩溃.
cond_,queue_ and mutex_
are member variable of MyQueue
.
So initially, all the threads are in waiting state. When the queue
has an item, one of the thread reads it and process it.
The problem occurs when the application is closed, gracefully or abruptly. There is a crash in the 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
作为条件变量,但不能解决问题. - 调用队列
dtor
中的_endthreadex(0).这样可以解决退出时的崩溃问题,但是我不认为这是正确的方法,因为我不确定哪个线程正在关闭.
- use
std::unique_ptr
for the condition variable but it didn't fix the issue. - call _endthreadex(0) in the
dtor
of the queue. This fixed the crash on exit, but i dont think this is the correct way as i am not sure which of thread is getting closed.
任何帮助将不胜感激.
推荐答案
这是crt错误.之所以崩溃,是因为std::condition_variable
析构函数是从DLL_PROCESS_DETACH
调用的.
this is crt bug. crash because std::condition_variable
destructor called from DLL_PROCESS_DETACH
.
MyQueue queue
被创建为全局变量,而cond_
被创建为全局变量MyQueue
MyQueue queue
is created as a global variable andcond_
, are member variable ofMyQueue
因为cond_
是DLL中的全局对象-在DLL_PROCESS_DETACH
because cond_
is global object in DLL - it destructor called on DLL_PROCESS_DETACH
清晰可见,所有均从_Cnd_destroy
开始(从条件变量的析构函数调用). crt内部调用 CreateThreadpoolWait
.调用TpAllocWait
.在此api的开头,存在下一行代码:
from stack trace clear visible that all begin from _Cnd_destroy
(called from destructor of conditional variable). crt internally call CreateThreadpoolWait
. which call TpAllocWait
. at very begin of this api exist next line of code:
if (RtlGetCurrentPeb()->Ldr->ShutdownInProgress) TppRaiseInvalidParameter();
因为 CreateThreadpoolWait
在ExitProcess
被调用之后调用(在堆栈跟踪ntdll!RtlExitUserProcess
中查找)(在DLL_PROCESS_DETACH
处理程序中)-ShutdownInProgress
已经true
并且结果被调用TppRaiseInvalidParameter
-从堆栈跟踪中再次可见
because CreateThreadpoolWait
called after ExitProcess
called (look in stack trace ntdll!RtlExitUserProcess
) (in DLL_PROCESS_DETACH
handler) - the ShutdownInProgress
already true
and as result TppRaiseInvalidParameter
called - again clear visible from your stack trace.
此处- std :: condition_variable析构函数在VS2012上崩溃此类崩溃的另一个示例. -如果您要查看崩溃的堆栈痕迹-您可以看到它完全相同(突出显示堆栈中的主要点)
here - std::condition_variable destructor crashes on VS2012 another example of this crash. - if you look to stack trace of the crash - you can view that it absolute the same (highlight main points in stack)
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
上崩溃
so only solution here - not use global condition_variable
object in dll - otherwise you got crash on DLL_PROCESS_DETACH
也来自 std :: condition_variable ::〜condition_variable
程序员必须确保没有线程尝试等待* this 一旦析构函数启动
The programmer must ensure that no threads attempt to wait on *this once the destructor has been started
,但对于您而言,这是不正确的.您的线程在等待条件变量cond_.wait(mlock);
的过程中终止.因此从条件变量的角度来看-线程仍在等待-它的数据(指向它的指针从它的堆栈中分配)链接到条件变量.您需要或以某种方式等待ExitProcess
调用之前的所有线程-但您不能从DLL_PROCESS_DETACH
之后执行此操作-为此exe必须在之前调用某些dll函数.还是不对dll全局条件变量使用wait
but this is not true in your case. your threads terminated during wait on conditional variable cond_.wait(mlock);
. so from conditional variable view - threads still waiting - it data (pointers to it blocks allocated from it stack) linked to conditional variable. you need or somehow unwait all threads before ExitProcess
call - but you can not do this from DLL_PROCESS_DETACH
which is called after this - for this exe must call some dll function before. or not use wait on dll global conditional variable
这篇关于在std :: condition_variable中调用后,由于INVALID PARAMETER导致应用程序崩溃的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!