• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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