zoukankan      html  css  js  c++  java
  • 可重入性和线程安全

    在本篇文章中,术语"可重入性"和"线程安全"被用来标记类与函数,以表明在多线程应用程序中它们可以被如何使用。
    - 一个线程安全的函数可以同时被多个线程调用,甚至这些调用者会使用共享的数据也没有问题,因为对共享数据的访问是串行化的(serialized)。
    - 一个可重入函数也可以同时被多个线程调用,但是每个调用者只能使用它自己的数据。
    因此,一个线程安全的函数总是可重入的,但一个可重入的函数并不一定是线程安全的。

    展开来说,一个可重入的类,指的是它的成员函数可以被多个线程安全地调用,只要每个线程使用这个类的不同的对象。而一个线程安全的类,指的是它的成员函数能够被多线程安全地调用,即使所有的线程都使用该类的同一个实例也没有关系。
    注意:有一些Qt的类本来就是被有意地设计为多线程使用的,只有这样的类才在文档中被标明为线程安全的。如果一个函数没有被标记为线程安全的或可重入的,它就不应该被不同的线程使用。如果一个类没有被标记为线程安全的或可重入的,该类的实例就不应该被多个线程访问。

    可重入性

    C++的类大多是可重入的,这只是因为它们只能访问它们自己的数据。任何线程都能访问一个可重入类的某实例的一个成员函数,只要此时没有其他线程能调用该实例的成员函数。比如,下面的Counter类就是可重入的: 

    1. class Counter
    2.  
      {
    3.  
      public:
    4.  
      Counter() { n = 0; }
    5. void increment() { ++n; }
    6.  
      void decrement() { --n; }
    7.  
      int value() const { return n; }
    8.   
    9. private:
    10.  
      int n;
    11.  
      };

    这个类不是线程安全的,因为如果多线程试图修改成员n的话,结果就是不确定的。这是因为++和--操作都不总是原子性的。它们一般被展开为3条机器指令:
    1. 将变量值装入寄存器
    2. 增或减寄存器中的值
    3. 将寄存器中的值装回主存
    如果线程A和线程B同时将变量的旧值装入寄存器,增加它们的寄存器,再装回主存,它们最终会互相重写,而变量仅仅被增加了一次!

    线程安全

    很明显,访问应该是串行的: 线程A必须在无中断的情况下执行完3个步骤(原子性),然后线程B才能开始执行它的步骤,或者反过来。一个使得类是线程安全的简单方法就是用一个QMutex来保护对数据成员的所有访问。

    1.  
      class Counter 
    2. {
    3.  
      public:
    4.  
      Counter() { n = 0; }
    5. void increment() { QMutexLocker locker(&mutex); ++n; }
    6.  
      void decrement() { QMutexLocker locker(&mutex); --n; }
    7.  
      int value() const { QMutexLocker locker(&mutex); return n; } 
    8. private: 
    9. mutable QMutex mutex;
    10.  
      int n;
    11.  
      };

    QMutexLocker类在其构造函数中自动锁定mutex,而在其析构函数中解锁。锁定mutex保证了其他线程的访问都将是串行化的。
    mutex数据成员被声明为mutable的,这是因为value()是一个const函数,但我们需要在其中lock和unlock这个mutex. 

    关于Qt类的注意事项

    许多Qt的类都是可重入的,但它们不是线程安全的,因为线程安全意味着要为锁定与解锁QMutex增加更多的开销。比如,QString是可重入的,但并不是线程安全的。你能够同时从多个线程访问不同的QString的实例,但你不能同时从多个线程访问QString的同一个实例(除非用QMutex保护访问)。
    有些Qt的类和函数是线程安全的。它们主要是线程相关类(比如,QMutex)和一些基本函数(比如,QCoreApplication::postEvent())。

    注意: 多线程领域中的术语并不是完全标准化的。POSIX使用的可重入和线程安全的定义和它在C API里面的定义就是有些不同的。当Qt和其他面向对象的C++的类库一起使用时,要注意定义是明确无歧义的。

  • 相关阅读:
    STM32 --- 什么时候打开复用IO的时钟(比如RCC_APB2Periph_AFIO)
    STM32 一直进入串口接收中断
    printf 中的 %.*s
    形参定义为二级指针,可以修改实参指针本身的值
    结构体和联合体配合使用
    自定义注解的实现思路
    log4j application.properties 配置文件
    外观设计模式
    适配器设计模式
    模版方法设计模式
  • 原文地址:https://www.cnblogs.com/lvdongjie/p/9678990.html
Copyright © 2011-2022 走看看