在std :: condition_variable中调用后,由于INVALID PARAMETER导致应用程序崩溃

时间:2018-05-25 07:52:27

标签: c++ multithreading winapi condition-variable

我有一个使用_beginthreadex生成大约20个线程的应用程序。所有线程都在等待队列填充,这是std::queueclass 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

我尝试的事情,

  1. 使用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` 作为条件变量,但它没有解决问题。
  2. 在队列的std::unique_ptr中调用_endthreadex(0)。这修复了退出时的崩溃,但我不认为这是正确的方法,因为我不确定哪个线程正在关闭。
  3. 任何帮助都将受到高度赞赏。

3 个答案:

答案 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。