QT的可重入性与线程安全
2016-05-27 22:50
316 查看
可重入性与线程安全(Reentrancy and Thread-Safety)
原文: http://doc.qt.io/qt-5.6/threads-reentrancy.html
在本篇文章中,术语"可重入性"和"线程安全"被用来标记类与函数,以表明在多线程应用程序中它们可以被如何使用。
- 一个线程安全的函数可以同时被多个线程调用,甚至这些调用者会使用共享的数据也没有问题,因为对共享数据的访问是串行化的(serialized)。
- 一个可重入函数也可以同时被多个线程调用,但是每个调用者只能使用它自己的数据。
因此,一个线程安全的函数总是可重入的,但一个可重入的函数并不一定是线程安全的。
展开来说,一个可重入的类,指的是它的成员函数可以被多个线程安全地调用,只要每个线程使用这个类的不同的对象。而一个线程安全的类,指的是它的成员函数能够被多线程安全地调用,即使所有的线程都使用该类的同一个实例也没有关系。
注意:有一些Qt的类本来就是被有意地设计为多线程使用的,只有这样的类才在文档中被标明为线程安全的。如果一个函数没有被标记为线程安全的或可重入的,它就不应该被不同的线程使用。如果一个类没有被标记为线程安全的或可重入的,该类的实例就不应该被多个线程访问。
1. 将变量值装入寄存器
2. 增或减寄存器中的值
3. 将寄存器中的值装回主存
如果线程A和线程B同时将变量的旧值装入寄存器,增加它们的寄存器,再装回主存,它们最终会互相重写,而变量仅仅被增加了一次!
mutex数据成员被声明为mutable的,这是因为value()是一个const函数,但我们需要在其中lock和unlock这个mutex.
有些Qt的类和函数是线程安全的。它们主要是线程相关类(比如,QMutex)和一些基本函数(比如,QCoreApplication::postEvent())。
注意: 多线程领域中的术语并不是完全标准化的。POSIX使用的可重入和线程安全的定义和它在C API里面的定义就是有些不同的。当Qt和其他面向对象的C++的类库一起使用时,要注意定义是明确无歧义的。
(完)
原文: http://doc.qt.io/qt-5.6/threads-reentrancy.html
在本篇文章中,术语"可重入性"和"线程安全"被用来标记类与函数,以表明在多线程应用程序中它们可以被如何使用。
- 一个线程安全的函数可以同时被多个线程调用,甚至这些调用者会使用共享的数据也没有问题,因为对共享数据的访问是串行化的(serialized)。
- 一个可重入函数也可以同时被多个线程调用,但是每个调用者只能使用它自己的数据。
因此,一个线程安全的函数总是可重入的,但一个可重入的函数并不一定是线程安全的。
展开来说,一个可重入的类,指的是它的成员函数可以被多个线程安全地调用,只要每个线程使用这个类的不同的对象。而一个线程安全的类,指的是它的成员函数能够被多线程安全地调用,即使所有的线程都使用该类的同一个实例也没有关系。
注意:有一些Qt的类本来就是被有意地设计为多线程使用的,只有这样的类才在文档中被标明为线程安全的。如果一个函数没有被标记为线程安全的或可重入的,它就不应该被不同的线程使用。如果一个类没有被标记为线程安全的或可重入的,该类的实例就不应该被多个线程访问。
可重入性
C++的类大多是可重入的,这只是因为它们只能访问它们自己的数据。任何线程都能访问一个可重入类的某实例的一个成员函数,只要此时没有其他线程能调用该实例的成员函数。比如,下面的Counter类就是可重入的:class Counter { public: Counter() { n = 0; } void increment() { ++n; } void decrement() { --n; } int value() const { return n; } private: int n; };这个类不是线程安全的,因为如果多线程试图修改成员n的话,结果就是不确定的。这是因为++和--操作都不总是原子性的。它们一般被展开为3条机器指令:
1. 将变量值装入寄存器
2. 增或减寄存器中的值
3. 将寄存器中的值装回主存
如果线程A和线程B同时将变量的旧值装入寄存器,增加它们的寄存器,再装回主存,它们最终会互相重写,而变量仅仅被增加了一次!
线程安全
很明显,访问应该是串行的: 线程A必须在无中断的情况下执行完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保证了其他线程的访问都将是串行化的。
mutex数据成员被声明为mutable的,这是因为value()是一个const函数,但我们需要在其中lock和unlock这个mutex.
关于Qt类的注意事项
许多Qt的类都是可重入的,但它们不是线程安全的,因为线程安全意味着要为锁定与解锁QMutex增加更多的开销。比如,QString是可重入的,但并不是线程安全的。你能够同时从多个线程访问不同的QString的实例,但你不能同时从多个线程访问QString的同一个实例(除非用QMutex保护访问)。有些Qt的类和函数是线程安全的。它们主要是线程相关类(比如,QMutex)和一些基本函数(比如,QCoreApplication::postEvent())。
注意: 多线程领域中的术语并不是完全标准化的。POSIX使用的可重入和线程安全的定义和它在C API里面的定义就是有些不同的。当Qt和其他面向对象的C++的类库一起使用时,要注意定义是明确无歧义的。
(完)
相关文章推荐
- 使用C++实现JNI接口需要注意的事项
- 关于指针的一些事情
- QT学习 第一章:基本对话框
- 使用Shiboken为C++和Qt库创建Python绑定
- c++ primer 第五版 笔记前言
- Qt 5.6更新至RC版,最终版本近在咫尺
- share_ptr的几个注意点
- Lua中调用C++函数示例
- Lua教程(一):在C++中嵌入Lua脚本
- Lua教程(二):C++和Lua相互传递数据示例
- C++联合体转换成C#结构的实现方法
- C++高级程序员成长之路
- C++编写简单的打靶游戏
- C++ 自定义控件的移植问题
- C++变位词问题分析
- C/C++数据对齐详细解析
- C++基于栈实现铁轨问题
- C++中引用的使用总结
- 使用Lua来扩展C++程序的方法
- C++中调用Lua函数实例