縱觀文檔編製,術語 可重入 and 綫程安全 用於標記類和函數,以指示它們如何用於多綫程應用程序:
因此, 綫程安全 函數始終 可重入 ,但 可重入 函數並不始終 綫程安全 .
By extension, a class is said to be 可重入 if its member functions can be called safely from multiple threads, as long as each thread uses a different instance of the class. The class is 綫程安全 if its member functions can be called safely from multiple threads, even if all the threads use the same instance of the class.
注意: Qt classes are only documented as 綫程安全 if they are intended to be used by multiple threads. If a function is not marked as thread-safe or reentrant, it should not be used from different threads. If a class is not marked as thread-safe or reentrant then a specific instance of that class should not be accessed from different threads.
C++ classes are often reentrant, simply because they only access their own member data. Any thread can call a member function on an instance of a reentrant class, as long as no other thread can call a member function on the
same
instance of the class at the same time. For example, the
Counter
下文類可重入:
class Counter { public: Counter() { n = 0; } void increment() { ++n; } void decrement() { --n; } int value() const { return n; } private: int n; };
The class isn't thread-safe, because if multiple threads try to modify the data member
n
, the result is undefined. This is because the
++
and
--
operators aren't always atomic. Indeed, they usually expand to three machine instructions:
If thread A and thread B load the variable's old value simultaneously, increment their register, and store it back, they end up overwriting each other, and the variable is incremented only once!
Clearly, the access must be serialized: Thread A must perform steps 1, 2, 3 without interruption (atomically) before thread B can perform the same steps; or vice versa. An easy way to make the class thread-safe is to protect all access to the data members with a QMutex :
class Counter { public: Counter() { n = 0; } void increment() { QMutexLocker locker(&mutex); ++n; } void decrement() { QMutexLocker locker(&mutex); --n; } int value() const { QMutexLocker locker(&mutex); return n; } private: mutable QMutex mutex; int n; };
The
QMutexLocker
class automatically locks the mutex in its constructor and unlocks it when the destructor is invoked, at the end of the function. Locking the mutex ensures that access from different threads will be serialized. The
mutex
data member is declared with the
可變
qualifier because we need to lock and unlock the mutex in
value()
, which is a const function.
很多 Qt 類 可重入 ,但它們並不 綫程安全 ,因為使它們綫程安全會招緻額外開銷,如重復鎖定和解鎖 QMutex 。例如, QString 可重入,但並不綫程安全。可以安全訪問 different 實例化的 QString 同時從多個綫程,但無法安全訪問 same 實例化的 QString 同時從多個綫程 (除非保護訪問自身采用 QMutex ).
某些 Qt 類和函數是綫程安全的。這些主要是綫程相關類 (如 QMutex ) 和基礎函數 (如 QCoreApplication::postEvent ()).
注意: Terminology in the multithreading domain isn't entirely standardized. POSIX uses definitions of reentrant and thread-safe that are somewhat different for its C APIs. When using other object-oriented C++ class libraries with Qt, be sure the definitions are understood.