Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does this C++ static singleton never stop?

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 implementation won't halt. The program never quits, it remains in a deadlock state at the end.

singleton.h:

#pragma once
#include <thread>
#include <atomic>

class Singleton
{
public:
    static Singleton& getInstance();

private:
    std::thread mThread;
    std::atomic_bool mRun;

    Singleton();
    ~Singleton();
    void threadFoo();
};

singleton.cpp

#include "singleton.h"

Singleton& Singleton::getInstance()
{
    static Singleton instance;
    return instance;
} 

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)
    {
    }
}

main.cpp

#include "singleton.h"

int main()
{
    Singleton::getInstance();
    return 0;
}

What I already know:

  • the thread terminates
  • the main thread is stuck in the join
  • it has something to do with the static, if i make the constructor public and create an instance of Singleton in main() it will correctly terminate.

Using Visual Studio 2012. Thanks for your advice.

like image 921
Xcessity Avatar asked Jun 13 '13 17:06

Xcessity


People also ask

Why is singleton instance static?

It is static so every instance of the Singleton type will use the same variable, hence the "singleton" pattern. Save this answer. Show activity on this post. Succinctly, Singleton is a design pattern used to ensure that only one instance of something is ever created within a given scope.

How can Singleton be prevented?

Suppose you serialize an object of a singleton class. Then if you de-serialize that object it will create a new instance and hence break the singleton pattern.

What is the disadvantage of Singleton design pattern?

They violate the single responsibility principle: by virtue of the fact that they control their own creation and lifecycle. They inherently cause code to be tightly coupled. This makes faking them out under test rather difficult in many cases. They carry state around for the lifetime of the application.

Why should we not use Singleton pattern?

By using singletons in your project, you start to create technical debt. Singletons tend to spread like a virus because it's so easy to access them. It's difficult to keep track of where they're used and getting rid of a singleton can be a refactoring nightmare in large or complex projects.


2 Answers

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.

like image 134
BitCortex Avatar answered Sep 28 '22 18:09

BitCortex


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.

like image 39
catscradle Avatar answered Sep 28 '22 18:09

catscradle