层次锁
实现:
#include <mutex>
using namespace std;
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 = 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()
{
if (this_thread_hierarchy_value != hierarchy_value)
throw std::logic_error("mutex hierarchy violated");
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);
这个类有四个数据成员:
- internal_mutex。一个互斥锁,我们的hierarchical_mutex就是对其进行封装
- this_thread_hierarchy_value。代表当前线程的层次值,因为是个static变量,所以是所有对象都共享这个变量的值。
- hierarchy_value。代表当前层次锁的层次值
- previous_hierarchy_value。当锁被获取时,记录获取之前的线程层次值
总的来说,多个层次锁获取的顺序只能是从高到低。每次获取层次锁,当前线程的层次值就变成该层次锁的层次值,锁内记录获取锁之前的线程层次值;当释放层次锁的时候,线程层次值恢复到获取锁之前。当发现线程层次值小于等于要获取的层次锁的值时,就会抛出异常。 由于获取锁的顺序是从高到低,所以释放锁的顺序只能是从低到高,当发现释放的锁的层次值和线程层次值不一致的时候,说明没有按照从低到高的顺序释放,因此也抛出异常。this_thread_hierarchy_value变量总是在内部互斥锁获取后,释放前修改,避免多线程未获取锁的状态下同时修改该值。 try_lock()方法和lock方法几乎一样,唯一不同的是调用了std::mutext.try_lock()尝试获取锁,如果失败返回false,如果成功获取则更新当前线程层次值。
简单调用:
hierarchical_mutex mutex1(1000);
int n;
void func1()
{
cout << "step1 func1 "<< "this_thread_hierarchy_value: " << hierarchical_mutex::get_this_thread_hierarchy_value()<<endl;
mutex1.lock();
cout << "step2 func1 " << "this_thread_hierarchy_value: " << hierarchical_mutex::get_this_thread_hierarchy_value() << endl;
n++;
Sleep(3000);
cout << n<<endl;
mutex1.unlock();
cout << "step3 func1 " << "this_thread_hierarchy_value: " << hierarchical_mutex::get_this_thread_hierarchy_value() << endl;
}
void func2()
{
cout << "func2 "<<"this_thread_hierarchy_value: " << hierarchical_mutex::get_this_thread_hierarchy_value() << endl;
}
int main()
{
std::thread thread1(func1);
std::thread thread2(func2);
thread1.join();
thread2.join();
}
一种可能的输出如下:
step1 func1 this_thread_hierarchy_value: 4294967295
step2 func1 this_thread_hierarchy_value: 1000
func2 this_thread_hierarchy_value: 4294967295
1
step3 func1 this_thread_hierarchy_value: 4294967295
我们可以看到,由于this_thread_hierarchy_value是thread_local类型的变量,所以在不同线程它的值是不一样的。在线程1内获取锁后,线程1层次值为1000,线程2的值则不受影响,层次锁释放后,线程1层次值恢复为最大值。
|