Why does this C++ static singleton never stop?

前端 未结 6 596
旧时难觅i
旧时难觅i 2020-12-28 08:48

i have implemented a singleton (static version) in C++. I know all the controversy about this pattern and potential thread-safety issues, but i am curious why this exact imp

相关标签:
6条回答
  • 2020-12-28 09:09

    Ok thank you all for your hints. Apparently this pattern implementation results in a deadlock on VC++.

    After doing some further research i found this implementation based on C++11 mechanics which is working in VC++.

    singleton.h

    #pragma once
    #include <thread>
    #include <atomic>
    #include <memory>
    #include <mutex>
    
    
    class Singleton
    {
    public:
        static Singleton& getInstance();
        virtual ~Singleton();
    
    private:
        static std::unique_ptr<Singleton> mInstance;
        static std::once_flag mOnceFlag;
        std::thread mThread;
        std::atomic_bool mRun;
    
        Singleton();
    
        void threadFoo();
    };
    

    singleton.cpp

    #include "singleton.h"
    
    std::unique_ptr<Singleton> Singleton::mInstance = nullptr;
    std::once_flag Singleton::mOnceFlag;
    
    
    Singleton& Singleton::getInstance()
    {
        std::call_once(mOnceFlag, [] { mInstance.reset(new Singleton); });
        return *mInstance.get();
    }
    
    
    Singleton::Singleton()
    {
        mRun.store(true);
        mThread = std::thread(&Singleton::threadFoo, this);
    }
    
    Singleton::~Singleton()
    { 
        mRun.store(false);
    
        if(mThread.joinable())
            mThread.join();
    }
    
    void Singleton::threadFoo()
    {
        while(mRun.load())
        {
        }
    }
    

    UPDATE

    It looks like Microsoft is aware of this issue. In the VC++ forums a user named "dlafleur" reported this post: https://connect.microsoft.com/VisualStudio/feedback/details/747145

    0 讨论(0)
  • 2020-12-28 09:10

    This deadlock bug is the same as in

    std::thread::join() hangs if called after main() exits when using VS2012 RC

    and it is not fixed in Visual Studio 2013.

    0 讨论(0)
  • 2020-12-28 09:14

    See [basic.start.term] in the Standard:

    If there is a use of a standard library object or function not permitted within signal handlers (18.10) that does not happen before (1.10) completion of destruction of objects with static storage duration and execution of std::atexit registered functions (18.5), the program has undefined behavior. [Note: If there is a use of an object with static storage duration that does not happen before the object’s destruction, the program has undefined behavior. Terminating every thread before a call to std::exit or the exit from main is sufficient, but not necessary, to satisfy these requirements. These requirements permit thread managers as static-storage-duration objects. —end note ]

    0 讨论(0)
  • 2020-12-28 09:26

    I've traced it down to void __cdecl _lock(int locknum) inside mlock.c. When main() ends, the main thread goes there and enters critical section EnterCriticalSection( _locktable[locknum].lock );. Then Singleton destructor gets called and the other thread tries to enter the same critical section, but can't, and so it starts waiting for main thread to leave the critical section. Main thread, in turn, waits for the other thread. So I guess it's a bug.

    0 讨论(0)
  • 2020-12-28 09:30

    On the main thread, after main() terminates, the CRT acquires the exit lock and calls your static instance destructor, which waits for your background thread to exit.

    On the background thread, after your thread function terminates, the CRT attempts to acquire the exit lock to do some thread termination work. This blocks forever because the exit lock is held by the main thread, which is waiting for this thread to exit.

    It's a simple deadlock that's caused by the CRT implementation. The bottom line is that you can't await thread termination in a static instance destructor on Windows.

    0 讨论(0)
  • 2020-12-28 09:30

    It seems to be fixed in Visual Studio 2015 and above, at least for this specific example.

    0 讨论(0)
提交回复
热议问题