std::get<C++11多线程库~线程间共享数据>(09):共享数据带来的问题(1)
1 #include <QCoreApplication> 2 3 /* 4 * 话题1:线程间共享数据 5 * a. 共享数据带来的问题 6 * b. 使用互斥量保护数据 7 * c. 数据保护的替代方案 8 * 9 * 多个线程只读的访问某一个相同的数据,不会出现问题; 10 * 多个线程有读有些的访问某一个相同的数据,可能会出现问题; 11 * 因此,当线程访问共享数据的时候,必须添加一些措施来约束对共享数据的访问。另外,某个线程修改了共享数据,还需要通知其他线程数据发生了变化。 12 * 13 * 1.1 共享数据带来的问题 14 * a. 条件竞争 15 * b. 避免恶性条件竞争 16 * 17 * 条件竞争(race condition):多个线程争夺同一资源。对共享资源的修改是否具备“原子性”非常关键,如果具备,则不会出问题,否则就是梦魇的开始。 18 * 数据竞争:C++标准中定义了一种特殊的条件竞争:并发的去修改一个独立对象,数据竞争是(可怕的)未定义行为的起因。 19 * 原子性:一个操作在CPU上一次能执行完毕,则称之为原子性操作,原子性操作是安全的。而非原子性操作,常常会因为“操作系统时间切片”的缘故,操作被切断,资源被另一线程 20 * 抢夺,非原子性操作是不安全的。 21 * 条件竞争通常是时间敏感的,所以程序以调试模式运行时,它们常会完全消失,因为调试模式会影响程序的执行时间(即使影响不多)。 22 * 23 * 解决恶性条件竞争,最简单的办法就是对数据结构采用某种保护机制,确保当存在写数据的线程,只有当前修改共享数据的线程能处理数据的中间状态, 24 * 而其他线程只能等待,对其他线程而言,能够访问的共享数据状态,要么被修改还未开始,要么被修改已经结束。 25 * C++标准库提供很多类似的机制,下面会逐一介绍: 26 * 第一种:对数据结构的设计进行修改,每个操作必须能完成一系列不可分割的变化,,这就是所谓的无锁编程。 27 * 第二种:使用事务的方式去处理数据结构的更新。类似于数据库事务的概念。 有一个相关的概念:“软件事务内存”(software transactional memory (STM))。 28 * 29 * 保护共享数据结构的最基本的方式,是使用C++标准库提供的互斥量。 30 * 31 * 32 */ 33 int main(int argc, char *argv[]) 34 { 35 QCoreApplication a(argc, argv); 36 37 return a.exec(); 38 }