3

I've faced a problem with std::conditional_variable notify() or notify_all() on Windows 7 when it called from destructor of static variable.

The object looks like this (logic is simplified):

class SomeObject
{
public:
    ~SomeObject()
    {
        StopThreadAndWait();
    }
    
    void StopThreadAndWait()
    {
            /* some logic  */
            m_stop = true;
            m_procesTasks.notify_one(); // <- the problem is here
            
            if (m_thread.joinable())
                m_thread.join();
    }
    
private:
    ...
    bool        m_stop;
    std::mutex  m_workQueueSync;
    
    std::thread m_thread;
    std::condition_variable m_procesTasks;
};

SomeObject -- is a static variable.

When we calling ~SomeObject() - the m_thread is already stopped. But on Windows 7 we came to a hang.

on the top of callstack: (this is THE ONLY thread of the application)

ntdll.dll!ZwReleaseKeyedEvent()
ntdll.dll!RtlpWakeConditionVariable()
ntdll.dll!RtlWakeConditionVariable()
MSVCP140D.dll!__crtWakeAllConditionVariable(_RTL_CONDITION_VARIABLE * pCond)
MSVCP140D.dll!Concurrency::details::stl_condition_variable_win7::notify_one()
....
ntdll.dll!RtlExitUserProcess()
...

I know, that synchronization in destructors of static objects - bad practice (it's a legacy code) There are a lot of ways to fix it.

But, it seems like a bug of implementation of the STL in 140 runtime for Win 7 (On Win 10 everything works fine). And if it is, I can't find anything about that on the internet

Upd:

Faced this issue on another project, so for anyone who may face this problem:

Problem: Seems, like some problem with the implementation of the conditional variable on Win7 (due to Concurrency::details::stl_condition_variable_win7::notify_one() )

Appears, when there is a condition variable, and threads which were waiting for that variable was, I suppose, terminated for some reason (in my case - due to the process shutdown)

In that case std::conditional_variable::notify() causes hang.

Possible Solutions

The best solution - just to fix the architecture, because threads within static objects - isn't the best approach.

Another option - to use boost instead of STL

Serhii Pavlenko
  • 121
  • 1
  • 6

1 Answers1

0

I experience the same problem, only on windows 7. Same code runs on Windows 10. It seems that the infrastructure for STL condition_variable has already been taken down somehow when we get to the notify_all (my case) or notify_one (here).

In my case there were 8 threads waiting but they are all dead when the program hangs, so notify_all did its job but never returned. In my call stack there is a function name containing win7 so there is most likely different code running in win7 vs win 10:

    ntdll.dll!ZwReleaseKeyedEvent()    Unknown
    ntdll.dll!string "Enabling heap debug options\n"() Unknown
    msvcp140d.dll!__crtWakeAllConditionVariable(_RTL_CONDITION_VARIABLE * pCond) Line 450   C++
    msvcp140d.dll!Concurrency::details::stl_condition_variable_win7::notify_all() Line 188  C++
    msvcp140d.dll!do_signal(_Cnd_internal_imp_t * cond, int all) Line 80    C++
    msvcp140d.dll!_Cnd_broadcast(_Cnd_internal_imp_t * cond) Line 101   C++
    cvie64.dll!std::condition_variable::notify_all() Line 596   C++
    cvie64.dll!ctpl::thread_pool::interrupt(bool kill) Line 166 C++
Bengt Gustafsson
  • 517
  • 4
  • 10
  • Yes, that's right. We have fixed it with boost::mutext & boost::condition_variable: due to the different implementations. We were unable to reproduce this bug anymore on Windows 7 after this. (I might be mistaken but in boost implementation, there is a validation before calling notify whenever some thread is waiting for that notify.) – Serhii Pavlenko Nov 23 '20 at 12:13