Сбой приложения из-за НЕПРАВИЛЬНОГО ПАРАМЕТРА после вызова в std :: condition_variable - PullRequest
0 голосов
/ 25 мая 2018

У меня есть приложение, которое порождает около 20 потоков, используя _beginthreadex.Все потоки ожидают заполнения очереди, которая является оберткой над std::queue: class MyQueue. queue создается как глобальная переменная, что-то вроде MyQueue processQueue

front функция MyQueue выглядит примерно так:

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

И push выглядит так:

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. вызовите _endthreadex (0) в dtor очереди.Это исправило сбой при выходе, но я не думаю, что это правильный путь, так как я не уверен, какой из потоков закрывается.

Любая помощь будет высоко оценена.

Ответы [ 3 ]

0 голосов
/ 25 мая 2018

это ошибка CRT.сбой, потому что деструктор std::condition_variable вызван из DLL_PROCESS_DETACH.

MyQueue queue создан как глобальная переменная, а cond_ являются переменными-членами MyQueue

потому что cond_ является глобальным объектом в DLL - его деструктор вызывается по DLL_PROCESS_DETACH

из трассировки стека, ясно видно, что все начинаются с _Cnd_destroy (вызывается из деструктора условной переменной).Крит внутренне позвонить CreateThreadpoolWait.который звонит TpAllocWait.в самом начале этого API существует следующая строка кода:

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

, потому что CreateThreadpoolWait вызывается после ExitProcess вызываемого (смотрите трассировку стека ntdll!RtlExitUserProcess) (в DLL_PROCESS_DETACH обработчик) - ShutdownInProgress уже true и, как результат, TppRaiseInvalidParameter вызван - снова очистить видимый из вашей трассировки стека.

здесь - std :: condition_variable destructor аварийно завершает работу на 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

, поэтому единственное решение здесь - не использовать глобальный condition_variable объект в dll -в противном случае вы получите сбой DLL_PROCESS_DETACH


также из std :: condition_variable :: ~ condition_variable

Программист должен убедиться, что ни один поток не пытаетсяподождать * этого после запуска деструктора

, но в вашем случае это не так.Ваши потоки прервались во время ожидания условной переменной cond_.wait(mlock);.Таким образом, с точки зрения условной переменной - потоки все еще ожидают - данные (указатели на блоки, выделенные из этого стека) связаны с условной переменной.вам нужно или как-то ожидать всех потоков перед вызовом ExitProcess - но вы не можете сделать это из DLL_PROCESS_DETACH, который вызывается после этого - для этого exe должен вызывать некоторую функцию dll до.или не использовать ожидание глобальной условной переменной dll

0 голосов
/ 29 мая 2018

Скомпилированный код с использованием vc140 с использованием Visual Studio 2015 и больше не было сбоев.В конце концов, похоже на ошибку visual studio 2013

0 голосов
/ 25 мая 2018

Вам придется разбудить ожидание выключения.cond_.notify_all() в деструкторе вашего класса исправит вашу проблему?

...