QT中可重入与线程安全概念解析

 

下面为QT帮助文档中的内容,简单记录供日后查看。

Reentrancy and Thread-Safety重入和线程安全
Throughout the documentation, the terms reentrant and thread-safe are used to mark classes and functions to indicate how they can be used in multithread applications:

通读整个文档,为了说明如何在多线程程序中使用可重入和线程安全,一直在用这两个词语来标记说明类和函数。


A thread-safe function can be called simultaneously from multiple threads, even when the invocations use shared data, because all references to the shared data are serialized.

即使函数里面用的是共享数据,一个线程安全的函数也可以同时被多个线程调用,因为所有对共享数据的引用都是有序的

(注:此处的有序是由于加锁的缘故,保证了某一时刻只有一个线程来操作数据)

 

A reentrant function can also be called simultaneously from multiple threads, but only if each invocation uses its own data.
Hence, a thread-safe function is always reentrant, but a reentrant function is not always thread-safe.

只有当每次调用函数用的是自己的数据时,一个可重入的函数才可以被多个线程同时调用。因此一个线程安全的函数总是可重入的,但是一个可重入的函数却不总是线程安全的。


By extension, a class is said to be reentrant 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 thread-safe if its member functions can be called safely from multiple threads, even if all the threads use the same instance of the class.

引申一下就是,一个类如果被认为是可重入的,也就是说如果每个线程使用不同的对象实例,那么每一个成员函数可以被多个线程安全调用一个类是线程安全的就必须满足,即使所有的线程都使用相同的类实例来调用他的成员函数也是安全的

Note: Qt classes are only documented as thread-safe 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. 

注:多线程中要使用一个QT的类,需要该类在文档中被标记为线程安全。如果一个函数没有被标记为线程安全或者可重入的,那么我们不应该在多个不同的线程中使用它。如果一个没有被标记为线程安全或者可重入的,那么我们不应该从不同的线程中访问一个明确定义的对象实例。
Reentrancy
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 below is reentrant:

C++类基本上都是可重入的,仅仅因为这些类只会访问自己的成员变量。只要没有其他线程同时调用这个类的相同实例的成员函数,任何线程可以通过一个可重入类的实例调用成员函数。比如,下面的计数器类就是可重入的。

 

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:

计数器类不是线程安全的,因为如果多线程试图去修改成员变量n, 结果是未定义的。这是因为++和--操纵不是原子操作。的确,++和--通常都会转换成三个机器指令
Load the variable's value in a register.        //将变量的值加载到寄存器中
Increment or decrement the register's value.   //递增或者递减寄存器的值
Store the register's value back into main memory.   //将寄存器的值存储回主内存


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! 

如果线程A和线程B同时加载同一个对象实例的同一个值n,递增寄存器,返回值,执行结束后,变量n可能只递增了一次
Thread-Safety
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:

很清楚的是,对n的访问必须序列化(串行访问,有序访问):在线程B执行对n的操作之前,线程A必须一次执行完步骤1、2、3也就是不被打断;反之亦然。保证类线程安全的一个简单的方法是通过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 mutable qualifier because we need to lock and unlock the mutex in value(), which is a const function. 

QMutexLocker类在他的构造函数中自动锁住mutex,函数结束时,在他的析构函数中自动解锁mutex。对mutex加锁保证了不同线程的访问被序列化。数据成员mutex添加了mutable修饰符,是因为我们需要在函数value中加锁和解锁mutex,而函数value是const函数。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值