C++并发编程2——为共享数据加锁(三)
正交——消除无关事务之间的影响,力求高内聚低耦合。死锁的概念略去不说,死锁有可能发生在使用多个互斥量的场景下,也可能存在没有使用互斥量的场景:
- 两个线程都在等待对方释放互斥量
- 两个线程都调用了对方的join()函数
- std::lock()函数
- std::unique_lock类
- std::lock()执行成功时,所有互斥量都已经被上锁,并且没有死锁问题
- std::lock()执行失败时,已被其上锁的互斥量都会被解锁
#include // std::cout
#include // std::thread
#include // std::mutex, std::lockclass some_big_object
{
public:
some_big_object(int a) :x(a) {}
void Print(){ std::cout << x << std::endl;
}
private:
int x;
};
class X
{
private:
some_big_object& some_detail;
std::mutex m;
public:
X(some_big_object & sd):some_detail(sd){}
friend void swap(X& lhs, X& rhs)
{
if(&lhs==&rhs)
return;
std::lock(lhs.m,rhs.m);
std::lock_guard lock_a(lhs.m,std::adopt_lock);
std::lock_guard lock_b(rhs.m,std::adopt_lock);
std::swap(lhs.some_detail,rhs.some_detail);
}
};
template
void swap(T& lhs,T& rhs);
template<>
void swap(some_big_object &x, some_big_object &y)
{
X a(x), b(y);
swap(a, b);
}int main ()
{
some_big_object a(1),b(2);
a.Print(), b.Print();
swap(a,b);
a.Print(), b.Print();
return 0;
}
上面一段代码使用了模板的偏特化特性,这里不需要深究,只需要知道swap(a, b)最终会调用X类的swap友元函数。在该友元函数中,std::lock()函数锁住两个互斥量,std::lock_guard负责unlock两个互斥量,如果不调用std::lock_guard(),需要手动unlock()。
std::adopt_lock
参数表示互斥量已经上锁,这里仅仅是不会重复上锁。下面两个例子起到相同作用。// example 1
std::mutex mtx;
std::lock(mtx);
// have to lock before the next sentence
std::lock_guard guard(mtx, std::adopt_lock);
// example 2
std::mutex mtx;
std::lock(mtx);
mtx.unlock();
避免死锁的一点建议 C++并发编程中给出了几点避免死锁的进阶指导:
- 1、避免嵌套锁
- 2、避免在持有锁时调用用户提供的代码
- 3、使用固定顺序获取锁
- 4、使用锁的层次结构
当代码试图对一个互斥量上锁,在该层锁已被低层持有时,上锁是不允许的。
hierarchical_mutex high_level_mutex(10000);
hierarchical_mutex low_level_mutex(7000);
hierarchical_mutex low_level_mutex(5000);
int do_low_level_stuff();
int low_level_func()
{
std::lock_guard lk(low_level_mutex);
return do_low_level_stuff();
}void high_level_stuff(int some_param);
void high_level_func()
{
std::lock_guard lk(high_level_mutex);
high_level_stuff(low_level_func());
}void middle_level_stuff(int some_param);
void middle_level_func()
{
std::lock_guard lk(middle_level_mutex);
middle_level_stuff(high_level_stuff());
}int main()
{
high_level_func();
middle_level_func();
}
【C++并发编程2——为共享数据加锁(三)】按照层次锁的原则,high_level_func()能够正确执行,而middle_level_func()不能正确执行:
- high_level_func()先获取到高层级的锁,然后获取到低层级的锁,符合原则
- middle_level_func()先获取低层级的锁,然后获取到高层级的锁,不符合原则
class hierarchical_mutex
{
std::mutex internal_mutex;
unsigned long const hierarchy_value;
unsigned long previous_hierarchy_value;
static thread_local unsigned long this_thread_hierarchy_value;
void check_for_hierarchy_violation()
{
if(this_thread_hierarchy_value <= hierarchy_value)
{
throw std::logic_error(“mutex hierarchy violated”);
}
}
void update_hierarchy_value()
{
previous_hierarchy_value=https://www.it610.com/article/this_thread_hierarchy_value;
this_thread_hierarchy_value=hierarchy_value;
}
public:
explicit hierarchical_mutex(unsigned long value):
hierarchy_value(value),
previous_hierarchy_value(0)
{}
void lock() {
check_for_hierarchy_violation();
internal_mutex.lock();
update_hierarchy_value();
}
void unlock()
{
this_thread_hierarchy_value=previous_hierarchy_value;
internal_mutex.unlock();
}
bool try_lock()
{
check_for_hierarchy_violation();
if(!internal_mutex.try_lock())
return false;
update_hierarchy_value();
return true;
} };
thread_local unsigned long hierarchical_mutex::this_thread_hierarchy_value(ULONG_MAX);
文章图片
关注微信公众号
推荐阅读
- 编程入门|这Python100道练习题及答案送给你,学完直接上手做项目
- JavaScript_牛客网_编程初学者入门训练(131-140题解)
- Linux系统编程---遍历目录
- #|邻接矩阵(构造无权图)
- 【C++】学生管理系统
- c|C/C++学习资源(百度云盘链接)
- c++编程|c++高精度算法
- c++ 操作redis实例
- 一文带你领略并发编程的内功心法
- Python编程学习(深度剖析shap.datasets.adult()源码中的X,y和X_display,y_display输出数区别)