线程间共享数据的问题
线程间共享数据的问题
- 多线程共享数据的问题多由数据改动引起
- 破坏数据结构不变量的恶性条件竞争是会引起问题的
- 解决的方式有,控制对数据结构的访问,有互斥实现,还有修改数据结构的设计及其不变量,由一连串不可拆分的改动完成.这通常被称为无锁编程,还有一种事务的方法,核心思想是单独操作然后一步提交
- 互斥,通过标记访问数据结构的所有代码,令各种线程在其上相互排斥,实现是利用锁mutex实现
- 为了防止忘记解锁,使用lock_guard,它使用了RAII的手法
- 运用互斥保护的代码应该不要往外界传出指向要保护数据的指针
- 要发现接口固有的条件竞争,如statck的top和pop,重新设计接口是唯一的解决方案
- 举例,线程安全的栈
#include <exception> #include <memory> #include <mutex> #include <stack> struct EmptyStack : std::exception { const char * what() const throw(); }; template<class T> class ThreadSafeStack { private: std::stack<T> data; mutable std::mutex m; public: ThreadSafeStack(){} ThreadSafeStack(const ThreadSafeStack & other) { std::lock_guard<std::mutex> lock(other.m); data = other.data; } ThreadSafeStack & operator=(const ThreadSafeStack&) = delete; void push(T newValue) { std::lock_guard<std::mutex> lock(m); data.push(std::move(newValue)); } std::shared_ptr<T> pop() { std::lock_guard<std::mutex> lock(m); if(data.empty()) throw EmptyStack(); std::shared_ptr<T> const res(std::make_shared<T>(data.top())); data.pop(); return res; } void pop(T& value) { std::lock_guard<std::mutex> lock(m); if(data.empty()) throw EmptyStack(); value = data.top; data.pop(); } bool empty() const { std::lock_guard<std::mutex> lock(m); return data.empty(); } }