前言
互斥锁的理解成本很低,带来的收益却很高——可以保证在多线程情况下安全地访问数据结构,而不会产生竞争条件或破坏不变量。
但互斥锁并非完美无缺,不正确地使用可能带来死锁,粗粒度地上锁将影响并发性。
如果能写出一个不使用锁的并发数据结构,则可避免上述互斥锁引入的问题,这样的数据结构被被称为无锁(lock-free)数据结构。
无锁结构的核心是前文提及的内存顺序属性,设计无锁结构时需要万分小心——它不仅很难正确实现,同时其内部bug很难稳定复现与定位原因。
一段经典的生产-消费场景代码如下:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15#include <vector>
#include <atomic>
#include <iostream>
std::vector<int> data;
std::atomic<bool> data_ready(false);
void reader_thread() {
while(!data_ready.load()) {
std::this_thread::sleep(std::milliseconds(1));
}
std::cout<<"The answer="<<data[0]<<"\n";
}
void writer_thread() {
data.push_back(42);
data_ready=true;
}
这里我们利用原子操作,保证了写入操作必然“先发生于”读取操作。不过,原子操作对顺序要求还有其他选项,它们构成了原子操作间的各种关系,下文将一一说明。
本篇为《Computer Network-A Top-Down Approach》第一章读书笔记。