gpt4 book ai didi

c++ - 调用 std::condition_variable 后因无效参数导致应用程序崩溃

转载 作者:行者123 更新时间:2023-11-28 04:39:38 28 4
gpt4 key购买 nike

我有一个使用 _beginthreadex 生成大约 20 个线程的应用程序。所有线程都在等待一个队列被填充,它是 std::queue 的包装器:class MyQueuequeue 是创建为全局变量,例如 MyQueue processQueue

MyQueuefront 函数看起来像,

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`

我尝试过的事情,

  1. 对条件变量使用 std::unique_ptr 但它没有解决问题。
  2. 在队列的 dtor 中调用 _endthreadex(0)。这修复了退出时的崩溃,但我不认为这是正确的方法,因为我不确定哪个线程正在关闭。

如有任何帮助,我们将不胜感激。

最佳答案

这是crt错误。崩溃是因为从 DLL_PROCESS_DETACH 调用了 std::condition_variable 析构函数。

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

因为 cond_ 是 DLL 中的全局对象 - 它的析构函数调用了 DLL_PROCESS_DETACH

从堆栈跟踪清楚可见,所有从 _Cnd_destroy 开始(从条件变量的析构函数调用)。 crt内部调用CreateThreadpoolWait .调用 TpAllocWait。在这个 api 的最开始存在下一行代码:

if (RtlGetCurrentPeb()->Ldr->ShutdownInProgress) TppRaiseInvalidParameter();

因为CreateThreadpoolWaitExitProcess 调用后调用(查看堆栈跟踪 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

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

但您的情况并非如此。您的线程在等待条件变量 cond_.wait(mlock); 期间终止。所以从条件变量的角度来看——线程仍在等待——它的数据(指向它的 block 的指针从它的堆栈分配)链接到条件变量。您需要或以某种方式在 ExitProcess 调用之前取消等待所有线程 - 但您不能从在此之后调用的 DLL_PROCESS_DETACH 执行此操作 - 因为此 exe 必须之前调用一些 dll 函数。或不使用 wait on dll 全局条件变量

关于c++ - 调用 std::condition_variable 后因无效参数导致应用程序崩溃,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50524156/

28 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com