1 /*
2 * Copyright (c) 2021 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #ifndef UTILS_BASE_SINGLETON_H
17 #define UTILS_BASE_SINGLETON_H
18
19 #include "nocopyable.h"
20 #include <mutex>
21 #include <memory>
22
23 namespace OHOS {
24
25 /**
26 * The purpose of the following macro definitions is to reduce the need
27 * to write repetitive code when defining singleton classes on the client side.
28 *
29 * Taking DelayedSingleton as an example, when declaring the target class as a
30 * singleton, add the DECLARE_DELAYED_SINGLETON (class_name) to the class
31 * declaration. When using the target singleton, call
32 * class_name::GetInstance()->.
33 */
34
35 /**
36 * @brief Sets `MyClass` as a `DelayedSingleton`.
37 *
38 * A `MyClass` object can be obtained by calling
39 * `DelayedSingleton<MyClass>::GetInstance()`.
40 *
41 * @param MyClass Target class to be set as a singleton.
42 *
43 * @note This macro definition should be used in the body of a class definition.
44 */
45 #define DECLARE_DELAYED_SINGLETON(MyClass)\
46 public:\
47 ~MyClass();\
48 private:\
49 friend DelayedSingleton<MyClass>;\
50 MyClass();
51
52 /**
53 * @brief Sets `MyClass` as a `DelayedRefSingleton`.
54 *
55 * A `MyClass` object can be obtained by calling
56 * `DelayedRefSingleton<MyClass>::GetInstance()`.
57 *
58 * @param MyClass Target class to be set as a singleton.
59 *
60 * @note This macro definition should be used in the body of a class definition.
61 */
62 #define DECLARE_DELAYED_REF_SINGLETON(MyClass)\
63 private:\
64 friend DelayedRefSingleton<MyClass>;\
65 ~MyClass();\
66 MyClass();
67
68 /**
69 * @brief Sets `MyClass` as a `Singleton`.
70 *
71 * A `MyClass` object can be obtained by calling
72 * `Singleton<MyClass>::GetInstance()`.
73 *
74 * @param MyClass Target class to be set as a singleton.
75 *
76 * @note This macro definition should be used in the body of a class definition.
77 */
78 #define DECLARE_SINGLETON(MyClass)\
79 private:\
80 friend Singleton<MyClass>;\
81 MyClass& operator=(const MyClass&) = delete;\
82 MyClass(const MyClass&) = delete;\
83 MyClass();\
84 ~MyClass();
85
86 /**
87 * @brief DelayedSingleton is a thread-safe, memory-safe lazy initialized
88 * singleton (with smart pointer and lock).
89 */
90 template<typename T>
91 class DelayedSingleton : public NoCopyable {
92 public:
93 /**
94 * @brief Creates a unique instance object.
95 *
96 * Use a smart pointer to manage resources. If all shared_ptrs are
97 * destroyed, the new object will also be deleted. This avoids memory leaks.
98 * A lock is added only when the pointer is empty, so as to avoid locking
99 * every time `GetInstance()` is called, reducing overhead of the lock.
100 */
101 static std::shared_ptr<T> GetInstance();
102 /**
103 * @brief Releases the ownership of managed object of the smart pointer.
104 *
105 * @note After this API is called successfully, 'GetInstance()' will create
106 * a new object. If the old object has an external 'std::shared_ptr'
107 * reference, you need to release it to maintain a singleton.
108 */
109 static void DestroyInstance();
110
111 private:
112 static std::shared_ptr<T> instance_; // Record the created DelayedSingleton instance.
113 static std::mutex mutex_; // Mutex, which guarantees that only one thread is accessing a common resource at any time.
114 };
115
116 template<typename T>
117 std::shared_ptr<T> DelayedSingleton<T>::instance_ = nullptr;
118
119 template<typename T>
120 std::mutex DelayedSingleton<T>::mutex_;
121
122 template<typename T>
GetInstance()123 std::shared_ptr<T> DelayedSingleton<T>::GetInstance()
124 {
125 if (instance_ == nullptr) {
126 std::lock_guard<std::mutex> lock(mutex_);
127 if (instance_ == nullptr) {
128 std::shared_ptr<T> temp(new (std::nothrow) T);
129 instance_ = temp;
130 }
131 }
132
133 return instance_;
134 }
135
136 template<typename T>
DestroyInstance()137 void DelayedSingleton<T>::DestroyInstance()
138 {
139 std::lock_guard<std::mutex> lock(mutex_);
140 if (instance_ != nullptr) {
141 instance_.reset();
142 instance_ = nullptr;
143 }
144 }
145
146 /**
147 * @brief DelayedRefSingleton is a thread-safe, lazy initialized
148 * singleton (with ordinary pointer and lock).
149 */
150 template<typename T>
151 class DelayedRefSingleton : public NoCopyable {
152 public:
153 /**
154 * @brief Creates a unique instance object.
155 *
156 * Pointer is used in the implementation, and the return value is a
157 * reference. It points to an instance that has a lifetime managed by
158 * the non-user code.
159 *
160 * @note The instance may not have been created at a certain point in time,
161 * or it may have been deleted, and therefore it is not possible to
162 * prohibit use of the delete keyword to destroy the object in advance.
163 */
164 static T& GetInstance();
165
166 private:
167 static T* instance_; // Record the DelayedRefSingleton instance created.
168 static std::mutex mutex_;
169 };
170
171 template<typename T>
172 T* DelayedRefSingleton<T>::instance_ = nullptr;
173
174 template<typename T>
175 std::mutex DelayedRefSingleton<T>::mutex_;
176
177 template<typename T>
GetInstance()178 T& DelayedRefSingleton<T>::GetInstance()
179 {
180 if (instance_ == nullptr) {
181 std::lock_guard<std::mutex> lock(mutex_);
182 if (instance_ == nullptr) {
183 instance_ = new T();
184 }
185 }
186
187 return *instance_;
188 }
189
190 /**
191 * @brief Singleton is a normally initialized singleton (without pointers and
192 * locks).
193 */
194 template<typename T>
195 class Singleton : public NoCopyable {
196 public:
197
198 /**
199 * @brief Gets a singleton instance object.
200 */
GetInstance()201 static T& GetInstance() { return instance_; }
202
203 private:
204 static T instance_;
205 };
206
207 template<typename T>
208 T Singleton<T>::instance_;
209 } // namespace OHOS
210
211 #endif
212