前面几篇笔记是关于线程运行的基本知识, 而从此开始, 需要很费脑分析而不再是前几篇笔记只用调下API即可. 很多自己都没看懂, 这里只是把看懂的先记下来
书里是先讲原子和内存, 这里换下顺序
要构建线程安全的数据结构, 关注几点:
- 若某线程破坏了数据结构的不变量, 保证其他线程不能看到
- 提供的操作应该完整,独立, 而非零散的分解步骤避免函数接口固有的条件竞争(比如之前提到的empty和top和pop)
一: 线程安全的容器栈threadsafe_stack
入门(3)里曾介绍过线程安全的stack容器, 这里把代码搬过来再分析
逐项分析, 该代码如何实现线程安全的
template<typename T>
class threadsafe_stack
{
private:
stack<T> data;
mutable mutex m;
public:
threadsafe_stack(){}
threadsafe_stack(const threadsafe_stack &other)
{
lock_guard lock1(other.m);
data=other.data;
}
threadsafe_stack &operator=(const threadsafe_stack &) = delete;
void push(T new_value)
{
lock_guard lock1(m);
data.push(move(new_value)); //1
}
shared_ptr<T> pop()
{
lock_guard lock1(m);
if (data.empty())
{
throw empty_stack(); //2
}
shared_ptr<T> const
res(make_shared<T>(move(data.top()))); //3
data.pop(); //4
return res;
}
void pop(T &value)
{
lock_guard lock1(m);
if (data.empty())
{
throw empty_stack();
}
value = move(data.top()); //5
data.pop(); //6
}
bool empty() const //7
{
lock_guard lock1(m);
return data.empty(