Qt线程安全和可重入

在整个文档中,术语可重入和线程安全用于标记类和函数,以指示如何在多线程应用程序中使用它们:

线程安全函数可以从多个线程同时调用,即使调用使用共享数据,因为对共享数据的所有引用都是序列化的。

可重入函数也可以从多个线程同时调用,但前提是每次调用都使用自己的数据。

因此,线程安全函数总是可重入的,但可重入函数并不总是线程安全的。

通过扩展,如果一个类的成员函数可以从多个线程安全地调用,只要每个线程使用一个不同的类实例,那么这个类就是可重入的。如果可以从多个线程安全地调用类的成员函数,则该类是线程安全的,即使所有线程都使用该类的同一实例。

注意:Qt类只有在被多个线程使用时才被记录为线程安全的。如果函数未标记为线程安全或可重入,则不应从不同的线程使用它。如果一个类没有被标记为线程安全的或可重入的,那么不应该从不同的线程访问该类的特定实例。

C++类通常是可重入的,仅仅因为它们只访问自己的成员数据。例如,下面的Counter类是可重入的:

  class Counter
  {
  public:
      Counter() { n = 0; }

      void increment() { ++n; }
      void decrement() { --n; }
      int value() const { return n; }

  private:
      int n;
  };

该类不是线程安全的,因为如果多个线程试图修改数据成员n的值,则结果是未定义的。这是因为++和- -运算符并不总是原子的。实际上,它们通常扩展为三条机器指令:

  1. 在寄存器中加载变量的值。

  2. 递增或递减寄存器中的值。

  3. 将寄存器的值存储回主存。

如果线程A和线程B同时加载变量n的旧值,在寄存器中递增它们的值,然后将其存储回去,它们最终会互相覆盖,变量只递增一次!

显然,访问必须序列化:线程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,并在函数末尾调用析构函数时解锁互斥锁。锁定互斥锁可确保不同线程的访问被序列化。互斥数据成员mutex是用可变限定符mutable声明的,因为我们需要锁定和解锁函数value()中的互斥锁mutex,而int value()是const函数,函数中的mutex是需要锁定和解锁的,是需要变化的,所以使用mutable修饰mutex。
在类中将成员函数修饰为const表明在该函数体内, 不能修改对象的数据成员而且不能调用非const函数。为什么不能调用非const函数?因为非const函数可能修改数据成员,const成员函数是不能修改数据成员的,所以在const成员函数内只能调用const函数。

许多Qt类是可重入的,但它们不是线程安全的,因为使它们成为线程安全的将导致重复锁定和解锁QMutex的额外开销。例如,QString是可重入的,但不是线程安全的。您可以同时从多个线程安全地访问QString的不同实例,但不能同时从多个线程安全地访问QString的同一实例(除非您自己使用QMutex保护访问)。

一些Qt类和函数是线程安全的。这些主要是与线程相关的类(例如QMutex)和基本函数(例如QCoreApplication::postEvent())。

注意:多线程领域的术语并不是完全标准化的。POSIX使用可重入和线程安全的定义,这两种定义在其C API中有些不同。当依靠QT来使用其他面向对象的C++类库时,请确保理解这些定义。

来源:Qt API

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

VectorAL

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值