Repository navigation
Expand file tree
/
Copy pathimpl_singleton_thread_safe_example.cpp
More file actions
99 lines (87 loc) · 2.8 KB
/
Copy pathimpl_singleton_thread_safe_example.cpp
File metadata and controls
99 lines (87 loc) · 2.8 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
#include <iostream>
#include <string>
#include <cstdio>
// #include <thread> // thread
#include "mingw.thread.h"
// #include <mutex>
#include "mingw.mutex.h"
/**
* The Singleton class defines the `GetInstance` method that serves as an
* alternative to constructor and lets clients access the same instance of this
* class over and over.
*/
class Singleton {
private:
static Singleton * pinstance_; // ensure multi-thread safety
static std::mutex mutex_; // ensure multi-thread safety
protected:
Singleton(const std::string value): value_(value) { }
~Singleton() {}
std::string value_;
public:
/**
* Singletons should not be cloneable.
*/
Singleton(Singleton &other) = delete;
/**
* Singletons should not be assignable.
*/
void operator=(const Singleton &) = delete;
/**
* This is the static method that controls the access to the singleton
* instance. On the first run, it creates a singleton object and places it
* into the static field. On subsequent runs, it returns the client existing
* object stored in the static field.
*/
static Singleton *GetInstance(const std::string& value);
/**
* Finally, any singleton should define some business logic, which can be
* executed on its instance.
*/
void doSomething() {
// ...
}
std::string value() const{
return value_;
}
};
/**
* Static methods should be defined outside the class.
*/
Singleton* Singleton::pinstance_{nullptr}; // ensure multi-thread safety
std::mutex Singleton::mutex_; // ensure multi-thread safet
/**
* The first time we call GetInstance we will lock the storage location
* and then we make sure again that the variable is null and then we
* set the value. RU:
*/
Singleton *Singleton::GetInstance(const std::string& value)
{
std::lock_guard<std::mutex> lock(mutex_); // ensure multi-thread safety
if (pinstance_ == nullptr) {
pinstance_ = new Singleton(value);
}
return pinstance_;
}
void ThreadFoo(){
// Following code emulates slow initialization.
std::this_thread::sleep_for(std::chrono::milliseconds(200));
Singleton* singleton = Singleton::GetInstance("FOO");
std::printf("%s\n", singleton->value().c_str());
}
void ThreadBar(){
// Following code emulates slow initialization.
std::this_thread::sleep_for(std::chrono::milliseconds(200));
Singleton* singleton = Singleton::GetInstance("BAR");
std::printf("%s\n", singleton->value().c_str());
}
int main() {
std::cout <<"√ two values are same: singleton reused \n" <<
"× two values are not same: 2 singletons created \n\n" <<
"RESULT:\n";
std::thread t1(ThreadFoo);
std::thread t2(ThreadBar);
t1.join();
t2.join();
return 0;
}