OSDN Git Service

race conditions fix for global statics created via Q_GLOBAL_STATIC() and Q_GLOBAL_STA...
authorIvailo Monev <xakepa10@gmail.com>
Wed, 8 Sep 2021 18:19:18 +0000 (21:19 +0300)
committerIvailo Monev <xakepa10@gmail.com>
Wed, 8 Sep 2021 18:26:46 +0000 (21:26 +0300)
Signed-off-by: Ivailo Monev <xakepa10@gmail.com>
src/core/global/qglobal.cpp
src/core/global/qglobal.h

index 3878f3f..4723c80 100644 (file)
@@ -1714,14 +1714,6 @@ bool QInternal::activateCallbacks(void **parameters)
 
     Use this macro to instantiate an object in a thread-safe way, creating
     a global pointer that can be used to refer to it.
-
-    \warning This macro is subject to a race condition that can cause the object
-    to be constructed twice. However, if this occurs, the second instance will
-    be immediately deleted.
-
-    See also
-    \l{http://www.aristeia.com/publications.html}{"C++ and the perils of Double-Checked Locking"}
-    by Scott Meyers and Andrei Alexandrescu.
 */
 
 /*!
@@ -1733,6 +1725,17 @@ bool QInternal::activateCallbacks(void **parameters)
     Use this macro to instantiate an object using the \a arguments specified
     in a thread-safe way, creating a global pointer that can be used to refer
     to it.
+*/
+
+/*!
+    \macro Q_GLOBAL_STATIC_WITH_INITIALIZER(type, name, initializer)
+    \internal
+
+    Declares a global static variable with the specified \a type and \a name.
+
+    Use this macro to instantiate an object using the \a initializer specified
+    in a thread-safe way, creating a global pointer that can be used to refer
+    to it.
 
     \warning This macro is subject to a race condition that can cause the object
     to be constructed twice. However, if this occurs, the second instance will
index 3d0ec11..716b1ff 100644 (file)
@@ -477,46 +477,33 @@ public:
     }
 };
 
-#define Q_GLOBAL_STATIC_INIT(TYPE, NAME)                                      \
-        static QGlobalStatic<TYPE > this_ ## NAME                             \
-                            = { QAtomicPointer<TYPE>(nullptr), false }
-
 #define Q_GLOBAL_STATIC(TYPE, NAME)                                           \
     static TYPE *NAME()                                                       \
     {                                                                         \
-        Q_GLOBAL_STATIC_INIT(TYPE, _StaticVar_);                              \
-        if (!this__StaticVar_.pointer && !this__StaticVar_.destroyed) {       \
-            TYPE *x = new TYPE;                                               \
-            if (!this__StaticVar_.pointer.testAndSetOrdered(nullptr, x))    \
-                delete x;                                                     \
-            else                                                              \
-                static QGlobalStaticDeleter<TYPE > cleanup(this__StaticVar_); \
-        }                                                                     \
+        static QGlobalStatic<TYPE > this__StaticVar_                          \
+            = { QAtomicPointer<TYPE>(new TYPE), false };                      \
+        static QGlobalStaticDeleter<TYPE > cleanup(this__StaticVar_);         \
         return this__StaticVar_.pointer;                                      \
     }
 
 #define Q_GLOBAL_STATIC_WITH_ARGS(TYPE, NAME, ARGS)                           \
     static TYPE *NAME()                                                       \
     {                                                                         \
-        Q_GLOBAL_STATIC_INIT(TYPE, _StaticVar_);                              \
-        if (!this__StaticVar_.pointer && !this__StaticVar_.destroyed) {       \
-            TYPE *x = new TYPE ARGS;                                          \
-            if (!this__StaticVar_.pointer.testAndSetOrdered(nullptr, x))    \
-                delete x;                                                     \
-            else                                                              \
-                static QGlobalStaticDeleter<TYPE > cleanup(this__StaticVar_); \
-        }                                                                     \
+        static QGlobalStatic<TYPE > this__StaticVar_                          \
+            = { QAtomicPointer<TYPE>(new TYPE ARGS), false };                 \
+        static QGlobalStaticDeleter<TYPE > cleanup(this__StaticVar_);         \
         return this__StaticVar_.pointer;                                      \
     }
 
 #define Q_GLOBAL_STATIC_WITH_INITIALIZER(TYPE, NAME, INITIALIZER)                  \
     static TYPE *NAME()                                                            \
     {                                                                              \
-        Q_GLOBAL_STATIC_INIT(TYPE, _StaticVar_);                                   \
+        static QGlobalStatic<TYPE > this__StaticVar_                               \
+            = { QAtomicPointer<TYPE>(nullptr), false };                            \
         if (!this__StaticVar_.pointer && !this__StaticVar_.destroyed) {            \
             QScopedPointer<TYPE > x(new TYPE);                                     \
             INITIALIZER;                                                           \
-            if (this__StaticVar_.pointer.testAndSetOrdered(nullptr, x.data())) { \
+            if (this__StaticVar_.pointer.testAndSetOrdered(nullptr, x.data())) {   \
                 static QGlobalStaticDeleter<TYPE > cleanup(this__StaticVar_);      \
                 x.take();                                                          \
             }                                                                      \