unique_lock
std::unique_lock比std::lock_guard更灵活,这种灵活性主要体现在以下几点:
- lock_guard在构造时或者构造前(std::adopt_lock)就已经获取互斥锁,并且在作用域内保持获取锁的状态,直到作用域结束;而unique_lock在构造时或者构造后(std::defer_lock)获取锁,在作用域范围内可以手动获取锁和释放锁,作用域结束时如果已经获取锁则自动释放锁。
- lock_guard锁的持有只能在lock_guard对象的作用域范围内,作用域范围之外锁被释放,而unique_lock对象支持移动操作,可以将unique_lock对象通过函数返回值返回,这样锁就转移到外部unique_lock对象中,延长锁的持有时间。
int n;
std::mutex some_mutex;
void prepare_data()
{
cout << n++ << endl;
}
void do_something()
{
cout << n++ << endl;
}
std::unique_lock<std::mutex> get_lock()
{
std::unique_lock<std::mutex> lk(some_mutex);//与lock_guard相同,构造时获取锁
cout << "owns_lock? " << lk.owns_lock() << endl;//1
prepare_data();
return lk;
}
int main()
{
//unique_lock基本使用
std::mutex mutex2;
std::unique_lock<std::mutex> lock2(mutex2, std::defer_lock);//告诉构造函数暂不获取锁
cout << "owns_lock? " << lock2.owns_lock() << endl;//0
lock2.lock();//手动获取锁
std::cout << "owns_lock? " << lock2.owns_lock() << endl;//1
lock2.unlock();//手动解锁
cout << "owns_lock? " << lock2.owns_lock() << endl;//0
//锁所有权转移到函数外部
std::unique_lock<std::mutex> lk(get_lock());//
do_something();
}
//析构
//lock2未获取锁mutex2,因此不会调用unlock
//lk对象持有锁some_mutex,调用unlock
由于unique_lock对象需要根据当前对象是否已经持有锁还是未持有进行判断从而执行适当的操作,因此比lock_guard占用空间稍大一点,效率稍低一点,std::unique_lock.owns_lock返回当前是否持有锁。
通常来说不应该在持有锁的期间执行消耗时间长的操作,此时unique_lock更加灵活,可以随时unlock,避免不相关的操作期间仍然持有锁。
std::unique_lock<std::mutex> my_lock(the_mutex);
some_class data_to_process = get_next_data_chunk();
my_lock.unlock();
result_type result = process(data_to_process);
my_lock.lock();
write_result(data_to_process, result);