第7章 设计无锁的并发数据结构

7.1 定义和结果

使用互斥元、条件变量以及future来同步数据的算法和数据结构被称为阻塞的算法和数据结构。

不使用阻塞库函数的数据结构和算法被称为非阻塞,但并非所有的这些数据结构都是无锁的。

7.1.1 非阻塞数据结构的类型

可以使用std::atomic_flag作为自旋锁的基本互斥元

class spinlock_mutex{
	
	std::atomic_flag flag;
	
	public:
		spinlock_mutex(): flag(ATOMIC_FLAG_INIT){}
		void lock(){
			while(flag.test_and_set(std::memory_order_acquire));
		}
		
		void unlock(){
			flag.clear(std::memory_order_release);
		}
};

采用循环的形式没有阻塞。

7.1.2 无锁数据结构

对于有资格成为无锁的数据结构,就必须能够让多于一个线程可以并发的访问此数据结构。在数据结构中使用比较/交换操作的算法经常在其中包含循环。使用比较/交换操作是因为有可能另一个线程正在同时修改数据,这种情况下,代码就需要在试图重新比较/交换前重做部分操作,如果比较/交换操作最终在其他线程都被中断的情况下成功,那么这种代码是无锁的。如果没有,最起码使用自旋,是非阻塞的而不是无锁的。

7.1.3 无等待的数据结构

无等待的数据结构时一种无锁的数据结构,并且有着额外的特性,每个访问数据结构的线程都能在有限数量的 步骤内完成它的操作,而不用管别的线程的行为。因为其他线程的冲突而可能卷入无限次重试的算法不是无等待的。

7.1.4 无锁数据结构的优点和缺点

    1. 使用无锁数据结构的原因就是为了实现最大程度的并发。
    2. 健壮性,一个无锁的数据结构在使用有锁的情况下,出现终止时,该数据结构就被永久的破坏了,而无锁数据结构只是破坏一个数据。
    3. 因为不是用锁,所以不会发生死锁
    4. 但是同时会出现活锁,即当两个线程要修改数据的时候,对于每一个线程由于另一线程所做的改变都会要求这个线程的操作被重新的执行,因此这两个线程会被无休止的重复。

7.2 无锁数据结构的例子

7.2.1 编写不用锁的线程安全栈

7.2.2 停止恼人的泄露:在无锁数据结构中管理内存

//代码有时间再补

posted @ 2020-01-06 20:02  楓羽  阅读(521)  评论(0编辑  收藏  举报