C++ STL之unique_lock与lock_guard


std::lock_guard
 

lock_guard - C++ Reference

用于托管一个mutex 变量,负责对齐加锁解锁。

A lock guard is an object that manages a mutex object by keeping it always locked.

On construction, the mutex object is locked by the calling thread, and on destruction, the mutex is unlocked. It is the simplest lock, and is specially useful as an object with automatic duration that lasts until the end of its context. In this way, it guarantees the mutex object is properly unlocked in case an exception is thrown.

Note though that the lock_guard object does not manage the lifetime of the mutex object in any way: the duration of the mutex object shall extend at least until the destruction of the lock_guard that locks it.

MyNote:

@ 有变量std::mutex myMutex; 需要用其保护一段critical section, 则需要在前后使用myMutex.lock(), myMutex.unlock()函数。缺点是lock和unlock需要成对出现,如果critical section出现异常,则后面的unlock不会执行了,容易导致死锁。使用std::lock_gard<mutex>  myLockGuard(myMutex) , (lock_guard的构造函数将myMutex上锁), 可以以并解决这些个缺点。

@ lock_guard object does not manage the lifetime of the mutex object in any way。 lock_guard的析构函数调用时,会unLock其托管的mutex变量,如果这时该变量已经消失了那就没有意义了。故,lock_guard保存的是其托管的mutex对象的引用/地址吧。


std::unique_lock

unique_lock - C++ Reference

A unique lock is an object that manages a mutex object with unique ownership in both states: locked and unlocked.

On construction (or by move-assigning to it), the object acquires a mutex object, for whose locking and unlocking operations becomes responsible.

The object supports both states: locked and unlocked.

This class guarantees an unlocked status on destruction (even if not called explicitly). Therefore it is especially useful as an object with automatic duration, as it guarantees the mutex object is properly unlocked in case an exception is thrown.

Note though, that the unique_lock object does not manage the lifetime of the mutex object in any way: the duration of the mutex object shall extend at least until the destruction of the unique_lock that manages it.

MyNote:

@ unique_lock的功能比lock_guard更多,从成员函数就可以看出


例子1: try_lock_for     

http://www.cplusplus.com/reference/mutex/unique_lock/try_lock_for/   

--std::unique_lock与std::timed_mutex联合使用的例子。的确,大家都需要一种带时间的mutex,当一段时间后还没有成功进入临界区时,即放弃加锁,否则一直阻塞在那里算个啥吗,也没有个提示。


Ref:

C++ 并发编程,std::unique_lock与std::lock_guard区别示例 - 旭东的博客 - 博客园

Difference between std::lock_guard and std::unique_lock  ::

One way of preventing data races between the threads is to use mutexes.

A mutex is usually associated with a resource. The thread, which locks the mutex, has granted access to the resource. No other thread can then lock the mutex because it is already locked (look figure below). Consequently, no other thread has an access to the resource guarded by the locked mutex. This is the mutual exclusion: only one thread has access to the resource at any given time.

We already spoke about the problems which appear when using mutexes in our code: remember Mutex and deadlock. There, we introduced the std::lock_guard class. But when we synchronized threads with a condition variable, we used similar class: std::unique_lock. What is the difference between these two classes?

The difference

One of the differences between std::lock_guard and std::unique_lock is that the programmer is able to unlock std::unique_lock, but she/he is not able to unlock std::lock_guard. Let’s explain it in more detail.

std::lock_guard

If you have an object

std::lock_guard guard1(mutex);

then the constructor of guard1 locks the mutex. At the end of guard1’s life, the destructor unlocks the mutex. There is no other possibility. In fact, the std::lock_guard class doesn’t have any other member function.

std::unique_lock

On the other hand, we have an object of std::unique_lock.

std::unique_lock guard2(mutex);

There are similarities with std::lock_guard class. The constructor of guard2 also locks the mutex and the destructor of guard2 also unlocks the mutex. But the std::unique_lock has additional functionalities.

The programmer is able to unlock the mutex with the help of the guard object

guard2.unlock();

This means that the programmer can unlock the mutex before the guard2’s life ends. After the mutex was unlocked, the programmer can also lock it again

guard2.lock();

We should mention that the std::unique_lock has also some other member functions. You can look it up here.

When to use std::unique_lock ?

There are at least two reasons for using std::unique_lock. Sometimes we are forced to use it: other functions require it as an input. And other times using std::unique_lock allows us to have more parallelizable code.

Higher parallelization

Let’s say that we have a long function. First part of the function accesses some shared resource and the second part locally processes the resource.

std::vector< int > vector; // shared between threads

...

int function(...)
{
    ...
    Getting int from the shared vector.
    ...
       
    ...
    Long, complicated computation with int. 
    This part does not depend on the vector. 
    ... 

}

A mutex must be locked just in the first part of the function, because we access the element of the vector. In the second part, the mutex doesn’t need to be locked anymore (because we don’t access any shared variable).

std::vector< int > vector; // shared between threads
std::mutex mutex; 

...

int function(...)
{
    ...
    std::unique_lock guard(mutex);
    Getting int from the shared vector.
    ...
       
    ...
    guard.unlock();
    Long, complicated computation with int. 
    This part does not depend on the vector. 
    ... 

}

In fact, it is preferable that the mutex is not locked in the second part, because then other threads can lock it. In principle, we would like that the locks last as little time as possible. This minimizes the time when threads are waiting to get a lock on the mutex and not doing any useful work. We obtain more parallelizable code.

Using functions that requires std::unique_lock

In Condition variable, we had to use the std::unique_lock, because std::condition_variable::wait(...) requires std::unique_lock as an input.

The std::condition_variable::wait(...) unlocks the mutex and waits for the std::condition_variable.notify_one() member function call. Then, wait(...) reacquires the lock and proceeds.

We recognize that wait(...) member function requires std::unique_lock. The function can not use usual std::lock_guard, because it unlocks/locks the mutex.

When to use std::lock_guard ?

The std::unique_lock has all of the functionalities of the std::lock_guard. Everything which is possible to do with std::lock_guard is also possible to do with std::unique_lock. So, when should we use std::lock_guard?

The rule of thumb is to always use std::lock_guard. But if we need some higher level functionalities, which are available by std::unique_lock, then we should use the std::unique_lock.

Summary

We learned the differences between the std::lock_guard and the std::unique_lock. We also listed some situations where we should use the std::unique_lock.

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

First Snowflakes

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值