避免死锁的一些注意事项

1. 避免嵌套锁, 如果每个线程都只占有一个锁, 则可以很大程度上避免死锁。
其死锁的情况是, 线程 1 依次获得 A 对象和 B 对象的锁, 然后决定等另一个线程的信号再继续, 从而先释放了 B 对象的的锁。
可是线程 2 需要同时拥有对象 A 和对象 B 的锁才能向线程 1 发信号。
从而导致, 线程 2 因无法获得对象 A 上的锁, 因而阻塞, 等待线程 1 释放对象 A 上的锁。 而同时线程 1 也一直阻塞, 等待线程 2 的信号, 因此不会释放对象 A 的锁。

2. 用固定的顺序获取锁
如果非要同时拥有多个锁, 同时无法拥有单个的锁, 那么最好的处理方式是以固定的顺序得到他们。典型的情况是在一个链表的结构中, 如果要取得节点 B 的锁, 那么需要先取得节点 A 的锁, 接着取得节点 C 的锁。

3. 设置优先级
当多个锁存在时, 设立优先级是个好主意,这样可以避免低优先级的 mutex 会先于高优先级的拥有锁。例如以下代码:

hierarchical_mutex high_level_mutex(10000);
hierarchical_mutex  low_level_mutex(5000);

int do_low_level_stuff();

int low_level_func()
{
    lock_guard<hierarchical_mutex> lk(low_level_mutex);
    return do_low_level_stuff();
}

void high_level_stuff(int some_param);

void high_level_func()
{
    lock_guard<hierarchical_mutex> lk(high_level_mutex);
    high_level_stuff(low_level_func);
}

void thread_a()
{
    high_level_func();
}

hierarchical_mutex other_mutex(100);
void do_other_stuff();

void other_stuff()
{
    high_levek_func();
    do_other_stuff();
}

void thread_b()
{
    lock_guard<hierarchical_mutex> lk(other_mutex);
    other_stuff();
}

其中, thread_a 就会成功, 而 therad_b 就会运行出错。
为啥呢?
因为它首先会拥有 other_mutex 的锁,other_mutex 的优先级只有 100, 却在  high_level_mutex 前得到锁, 这违反了优先级, 所以 hierarchical_mutex 会报错并抛出一个异常, 然后退出程序。
上文中提到的 hierarchical_mutex 并不是标准库的一部分, 但是可以很容易的实现:

class hierarchical_mutex
{
    mutex                                   internal_mutex;
    unsigned long const                     hierarchy_value;
    unsigned                                previous_hierarchy_value;
    static  thread_local unsigned long    this_thread_hierarchy_value;
    
    // second mutex must now be less than 
    //that of the mutex already held 
  //in order for the check to pass
void check_for_hierarcy_violation() { if(this_thread_hierarchy_value <= hierarchy_value){ throw std::logic_error("mutex hierarchical violated"); } } void update_hierarchy_value() { previous_hierarchy_value = 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_hierarcy_violation(); internal_mutex.lock(); update_hierarchy_value(); } void unlock() { this_thread_hierarchy_value = previous_hierarchy_value; internal_mutex.unlock(); } bool try_lock() { check_for_hierarcy_violation(); if(!internal_mutex.try_lock()){ return false; } update_hierarchy_value(); return true; } }; // initialized to the maximum value, // so initially any mutex can be locked thread_local unsigned long hierarchical_mutex::this_thread_hierarchy_value(ULONG_MAX);

 

posted @ 2015-02-24 17:30  wu_overflow  阅读(272)  评论(0编辑  收藏  举报