Application crash due to INVALID PARAMETER after call in std::condition_variable

杀马特。学长 韩版系。学妹 提交于 2019-12-25 01:39:01

问题


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

The front function of MyQueue looks something like,

std::unique_lock<std::mutex> mlock(mutex_);
        while (queue_.empty())
        {
            cond_.wait(mlock);
        }
        auto item = queue_.front();
        queue_.pop();
        return item;

And push looks like:

std::unique_lock<std::mutex> mlock(mutex_);
        queue_.push(item);
        mlock.unlock();
        cond_.notify_one();

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.

Entire stack from the crash dump

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`

Things i tried,

  1. use std::unique_ptr for the condition variable but it didn't fix the issue.
  2. 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.

Any help would be highly appreciated.


回答1:


this is crt bug. crash because std::condition_variable destructor called from DLL_PROCESS_DETACH.

MyQueue queue is created as a global variable and cond_, are member variable of MyQueue

because cond_ is global object in DLL - it destructor called on DLL_PROCESS_DETACH

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

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.

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

so only solution here - not use global condition_variable object in dll - otherwise you got crash on DLL_PROCESS_DETACH


also from std::condition_variable::~condition_variable

The programmer must ensure that no threads attempt to wait on *this once the destructor has been started

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




回答2:


You'll have to wake up the wait for shutdown. cond_.notify_all() in destructor of your class fix your problem?




回答3:


Compiled code using vc140 using visual studio 2015 and there was no more crash. Looks like visual studio 2013 bug after all.



来源:https://stackoverflow.com/questions/50524156/application-crash-due-to-invalid-parameter-after-call-in-stdcondition-variable

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!