为了避免死锁,可以规定加锁的顺序,因此可以使用层次锁来实现。通过给互斥量封装层次值之一属性,可以确保层次值高的线程可以获得层次值低的锁,反之则不行。简单代码实现如下,可以使用stack来保存已经获得锁的层次值。
class HierarchicalMutex {
private:
mutex inter_mutex_;
unsigned long const level_value_;
unsigned long previous_value_;
static thread_local unsigned long this_thread_value_;
public:
HierarchicalMutex(unsigned long level_value) :level_value_(level_value),previous_value_(0) {}
void checkLock() {
//this_thread_value_是线程本地变量,所以每个线程各存一份,用来保存线程自带的层次值
//线程获得锁之后,该层次值就成了该线程自带的值了,当该线程试图去获取层次值更高的锁时,这样是不允许的
if (this_thread_value_ <= level_value_)
{
throw logic_error("can not lock\n");
}
}
void lock() {
checkLock();
inter_mutex_.lock();
//获得锁之后,首先将线程原有的值保存下来,然后如果其再去获得一个层次值较小的锁的话,更新值为更小的那个值
previous_value_ = this_thread_value_;
this_thread_value_ = level_value_;
}
void unlock() {
//如果获得的层次较小的锁释放了,那么该线程的层次值恢复成原有的值
this_thread_value_ = previous_value_;
inter_mutex_.unlock();
}
bool trylock() {
checkLock();
if (!inter_mutex_.try_lock())
{
return false;
}
previous_value_ = this_thread_value_;
this_thread_value_ = level_value_;
return true;
}
};
thread_local unsigned long HierarchicalMutex::this_thread_value_ = ULONG_MAX;
HierarchicalMutex high_lock(10000);
HierarchicalMutex low_lock(500);
void low_func();
void high_func() {
lock_guard<HierarchicalMutex> lg(high_lock);
cout << "thread : " << this_thread::get_id() << "get the high lock" << endl;
low_func();
}
void low_func() {
lock_guard<HierarchicalMutex> lg(low_lock);
cout<< "thread : " << this_thread::get_id() << "get the low lock" << endl;
}
int main() {
thread t(high_func);
t.join();
return 0;
}