可重入性与线程安全性
在整个文档中,“可重入”和“线程安全”这两个术语用于标记类和函数,以说明它们在多线程应用程序中的使用方式:
- 线程安全的函数可以被多个线程同时调用,即使这些调用使用了共享数据,因为对共享数据的所有引用都经过了串行化处理。
- 重入函数也可以从多个线程同时调用,但前提是每个调用都使用自己的数据。
因此,线程安全的函数总是可重入的,但可重入的函数并不总是线程安全的。
由此延伸,如果一个类的成员函数可以安全地从多个线程调用(只要每个线程使用该类的不同实例),则该类被称为可重入的。如果该类的成员函数可以安全地从多个线程调用(即使所有线程都使用该类的同一实例),则该类是线程安全的。
注意: 只有当Qt 类旨在供多个线程使用时,才会被文档标注为线程安全。如果某个函数未被标记为线程安全或可重入,则不应从不同的线程中调用它。 如果一个类未被标记为线程安全或可重入,则不应从不同的线程访问该类的特定实例。
可重入性
C++ 类通常是可重入的,原因很简单:它们仅访问自身的成员数据。任何线程都可以调用可重入类实例上的成员函数,只要没有其他线程在同一时间调用该类同一实例上的成员函数即可。例如,下面的Counter 类就是可重入的:
class Counter
{
public:
Counter() { n = 0; }
void increment() { ++n; }
void decrement() { --n; }
int value() const { return n; }
private:
int n;
};该类并非线程安全的,因为如果多个线程尝试修改数据成员 `n`,结果将未定义。这是因为 `++ ` 和 `-- ` 运算符并不总是原子的。事实上,它们通常会展开为三条机器指令:
- 将变量的值加载到寄存器中。
- 对寄存器的值进行递增或递减。
- 将寄存器的值写回主内存。
如果线程 A 和线程 B 同时加载变量的旧值、增量或减量其寄存器值,并将其写回主内存,它们最终会相互覆盖,而该变量仅被增量一次!
线程安全
显然,访问必须被串行化:线程 A 必须在不被中断的情况下(原子地)执行步骤 1、2、3,然后线程 B 才能执行相同的步骤;反之亦然。使类具有线程安全性的一个简单方法是,使用 `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;
};QMutexLocker 类会在其构造函数中自动锁定互斥锁,并在函数结束时调用析构函数时解锁。锁定互斥锁可确保来自不同线程的访问被序列化。 数据成员mutex 使用mutable 修饰符进行声明,因为我们需要在value() 中锁定和解锁互斥锁,而该函数是一个const函数。
关于 Qt 类的说明
许多 Qt 类是可重入的,但它们并非线程安全的,因为要使其线程安全会带来反复锁定和解锁QMutex 的额外开销。例如,QString 是可重入的,但并非线程安全的。 您可以安全地从多个线程同时访问QString 的不同实例,但无法安全地从多个线程同时访问QString 的同一个实例(除非您使用QMutex 自行保护这些访问)。
某些 Qt 类和函数是线程安全的。这些主要是与线程相关的类(例如QMutex )和基础函数(例如QCoreApplication::postEvent())。
注意: 多线程领域的术语 尚未完全标准化。POSIX 在其 C API 中对“可重入”和“线程安全”的定义略有不同。当将其他面向对象的 C++ 类库与 Qt 结合使用时,请确保理解这些定义。
© 2026 The Qt Company Ltd. Documentation contributions included herein are the copyrights of their respective owners. The documentation provided herein is licensed under the terms of the GNU Free Documentation License version 1.3 as published by the Free Software Foundation. Qt and respective logos are trademarks of The Qt Company Ltd. in Finland and/or other countries worldwide. All other trademarks are property of their respective owners.