0

I have implemented a Meyer's singleton pattern. And I try to do some stuff testing it in a multithreading environment. Here is how I implemented the class in C++.

#include<thread>
#include<mutex>
class singleton {
public:
  static singleton& instance() {
    std::lock_guard<std::mutex> lck(mtx);
    static singleton *my = new singleton;
    return *my;
  }
private:
  static std::mutex mtx;
  singleton() {}
  ~singleton() {}
  singleton(const singleton &) {}
  singleton& operator=(const singleton &) {}
};

But when I compile this with g++ -std=c++11 singleton.cpp -o singleton -lpthread, it says

/tmp/ccfEBnmN.o: In function `singleton::instance()':
singleton.cpp(.text._ZN11singleton12instanceEv[_ZN11singelton12instanceEv]+0x10):
undefined reference to `singleton::mtx' collect2: error: ld returned 1 exit status

I understand this might be some problem in design, since without initializing the first singleton instance how could we get the mtx. If in this case, my question comes to how to implement a thread safe singleton class based on my code? How do we initialized the mtx in my singleton class?

I know there is a traditional way to create a singleton pattern by maintaining a static pointer points to the singleton class. But indeed that is not "so" thread safe. Even applying the double check mechanism in the instance() method.

Lawliet
  • 13
  • 5
  • It has nothing to do with your singleton implementation per se. Also `Scott Meyer's` proposal ends up a bit different IIRC: [Using a singleton in C++](http://stackoverflow.com/questions/25092657/using-a-singleton-in-c/25092703#25092703). The current standard guarantees the atomic instantiation. – πάντα ῥεῖ Dec 19 '14 at 00:09

2 Answers2

3

You've declared mtx in singleton, but failed to define it, which has to be outside of singleton, something like this:

std::mutex singleton::mtx;

This should be in a source file, not a header though (otherwise you'll get multiple definition errors when/if you include the header in more than one source file).

Second point: what you're showing is not a Meyer's singleton pattern at all. For a Meyer's singleton, you define a static instance of the singleton inside the function:

static singleton &instance() { 
    static singleton my;

    return my;
}

Using this, it's not clear that you really need a mutex at all.

Jerry Coffin
  • 476,176
  • 80
  • 629
  • 1,111
  • Yes, I realized that `mtx` is a static member that needs a definition. So your point is a Meyer's singleton does NOT need a mutex to hold its access from different threads? I read through some article talks about Meyer's and they say it's thread safe in C++11. I doubt it and just wish to test. – Lawliet Dec 19 '14 at 00:05
  • @Lawliet: yes--when you use `new` to allocate the object, you need to ensure that only one thread ever allocates the object, and all other calls return a reference to that one object. With a Meyer's singleton, the compiler assures that the object is created before entry to the function, so you don't need a mutex to do that (provided the compiler does its job correctly). – Jerry Coffin Dec 19 '14 at 00:07
  • Wow that's neat! Thank you for your answer. A question to your 2nd point, without a `new`, the `singleton my` object should be created in the stack, right? what if other threads calling `singleton::instance()`? Are they able to access to the singleton object? – Lawliet Dec 19 '14 at 00:12
  • @Lawliet: Since the object is defined as `static`, it has static storage duration (probably not on the stack) but local visibility (i.e., its *name* is only visible inside that function). So yes, the same instance is accessible from all threads. – Jerry Coffin Dec 19 '14 at 00:15
  • This makes sense to me. I ignore the `static` ;-) – Lawliet Dec 19 '14 at 00:18
0

Your static data member mtx needs a definition. Place this in your source file:

std::mutex singleton::mtx;

More accurately, std::lock_guard<std::mutex> lck(mtx) odr-uses mtx so its definition is required. You get a link-time error when the linker cannot resolve the reference.

Also note that in C++11 the initialization of an object with static storage duration is thread safe, you don't need a mutex.

David G
  • 94,763
  • 41
  • 167
  • 253
  • So in this case my singleton is thread safe itself without any protection of introducing mutex? That sounds the line `static singleton *my` done the same job as a `scoped_lock(mutex)`. – Lawliet Dec 19 '14 at 00:08
  • @Lawliet Yes, it's thread safe without the mutex. – David G Dec 19 '14 at 00:09