Qt 多线程之可重入与线程安全

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,结果未定义。这是因为c++中的++和--操作符不是原子操作。实际上,它们会被扩展为三个机器指令:

1,把变量值装入寄存器

2,增加或减少寄存器中的值

3,把寄存器中的值写回内存

假如线程A与B同时装载变量的旧值,在寄存器中增值,回写。他们写操作重叠了,导致变量值仅增加了一次。很明显,访问应该串行化:A执行123步骤时不应被打断。使这个类成为线程安全的最简单方法是使用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进行加锁与解锁操作,而value()是一个const函数。

大多数Qt类是可重入,非线程安全的。有一些类与函数是线程安全的,它们主要是线程相关的类,如QMutex,QCoreApplication::postEvent()。

线程与QObjects

QThread 继承自QObject,它发射信号以指示线程执行开始与结束,而且也提供了许多slots。更有趣的是,QObjects可以用于多线程,这是因为每个线程被允许有它自己的事件循环。
QObject 可重入

QObject是可重入的。它的大多数非GUI子类,像QTimer,QTcpSocket,QUdpSocket,QHttp,QFtp,QProcess也是可重入的,在多个线程中同时使用这些类是可能的。需要注意的是,这些类被设计成在一个单线程中创建与使用,因此,在一个线程中创建一个对象,而在另外的线程中调用它的函数,这样的行为不能保证工作良好。有三种约束需要注意:

1,QObject的孩子总是应该在它父亲被创建的那个线程中创建。这意味着,你绝不应该传递QThread对象作为另一个对象的父亲(因为QThread对象本身会在另一个线程中被创建)

2,事件驱动对象仅仅在单线程中使用。明确地说,这个规则适用于"定时器机制“与”网格模块“,举例来讲,你不应该在一个线程中开始一个定时器或是连接一个套接字,当这个线程不是这些对象所在的线程。

3,你必须保证在线程中创建的所有对象在你删除QThread前被删除。这很容易做到:你可以run()函数运行的栈上创建对象。

尽管QObject是可重入的,但GUI类,特别是QWidget与它的所有子类都是不可重入的。它们仅用于主线程。正如前面提到过的,QCoreApplication::exec()也必须从那个线程中被调用。实践上,不会在别的线程中使用GUI类,它们工作在主线程上,把一些耗时的操作放入独立的工作线程中,当工作线程运行完成,把结果在主线程所拥有的屏幕上显示。

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值