1. std::mutex
类似函数std::recursive_mutex 允许同一个线程多次获取同一个互斥量
头文件#include <mutex>
mutex::lock(),给共享内存加锁
...
... //待保护代码或者共享内存等等
...
mutex::unlock(),给共享内存解锁
比如:
std::mutex m;
m.lock();
...
m.unlock();
2. std::lock_guard<std::mutex> (模板类)
头文件#include <mutex>
比如:
1)
std::mutex m;
{
std::lock_gurad<std::mutex> lguard(m); //类中默认加锁作用域,作用域执行完毕类析构中自动解锁
... //作用域在大括号中,作用域结束,lguard自动unlock。
}
2)
std::mutex m;
{
m.lock();
std::lock_guard<std::mutex> lguard(m, std::adopt_lock); //使用adopt_lock选项默认为未加锁,但是执行完作用域类析构函数中自动解锁。
... //作用域在大括号内,作用域结束,lguard自动unlock。
}
3)
std::mutex m;
{
std::lock_guard<std::mutex> lguard(m); //默认已经加锁
std::mutex *pmtx = lguard.release(); //解除lguard和m之间的关联关系,此时m已经加锁,并未解锁,所以后面需要解锁
... //作用域在大括号内,作用域结束,lguard自动unlock。
pmtx->unlock();
}
3. std::unique_lock<std::mutex>
头文件#include <mutex>
- 拥有方法std::unique_lock<std::mutex>::owns_lock(),判断当前是否锁定该锁。
- 拥有方法std::unique_lock<std::mutex>::try_lock(),尝试加锁,如果返回true则加锁成功,否则加锁失败,不阻塞。
- 拥有方法std::unique_lock<std::mutex>::release(),返回它管理的mutex对象指针,并释放所有权;也就是说,这个unique_lock和mutex不在有关系。
比如:
1)
std::mutex m;
{
std::unique_lock<std::mutex> uguard(m); //类中默认加锁作用域,作用域执行完毕类析构中自动解锁
... //作用域在大括号中,作用域结束,uguard自动unlock。
}
2)
std::mutex m;
{
m.lock();
std::unique_lock<std::mutex> uguard(m, std::adopt_lock); //使用adopt_lock选项默认为未加锁,但是执行完作用域类析构函数中自动解锁。
... //作用域在大括号内,作用域结束,uguard自动unlock。
}
3)
std::mutex m;
{
std::unique_lock<std::mutex> uguard(m, std::try_to_lock); //解决一个线程加锁后占用事件较长,另一个线程等待较长时间的问题
... //作用域在大括号内,作用域结束,uguard自动unlock。
}
4)
std::mutex m;
{
std::unique_lock<std::mutex> uguard(m, std::defer_lock); //1. 解决线程临时需要释放锁,之后再次加锁的情况。2. 如果后面不使用lock和unlock功能和示例3一样。
uguard.lock(); //加锁
... //作用域在大括号内,作用域结束,uguard自动unlock。
另外也可以手动lock和unlock。
uguard.unlock();
...
...
uguard.lock();
...
...
uguard.unlock();
}
5)
std::mutex m;
{
std::unique_lock<std::mutex> uguard(m, std::defer_lock); //1. 解决线程临时需要释放锁,之后再次加锁的情况。2. 如果后面不使用lock和unlock功能和示例3一样。
uguard.lock(); //加锁
... //作用域在大括号内,作用域结束,uguard自动unlock。
if( uguard.owns_lock() == true){
... //加锁成功,执行共享内存代码
}
else{
... //加锁没有成功
}
}
6)
std::mutex m;
{
std::unique_lock<std::mutex> uguard(m, std::defer_lock); //1. 解决线程临时需要释放锁,之后再次加锁的情况。2. 如果后面不使用lock和unlock功能和示例3一样。
... //作用域在大括号内,作用域结束,uguard自动unlock。
if(uguard.try_lock() == true){
... //加锁成功,执行共享内存代码
}
else{
... //加锁没有成功
}
}
7)
std::mutex m;
{
std::unique_lock<std::mutex> uguard(m); //默认已经加锁
std::mutex *pmtx = uguard.release(); //解除uguard和m之间的关联关系,此时m已经加锁,并未解锁,所以后面需要解锁
... //作用域在大括号内,作用域结束,uguard自动unlock。
pmtx->unlock();
}
4. std::lock()函数
功能:一次加多把锁,避免死锁
头文件:#include <mutex>
比如:
1)
std::mutex m1, m2;
std::lock(m1, m2) //m1,m2同时上锁
... //访问共享变量
m1.unlock();
m2.unlock();
2)
std::mutex m1, m2;
std::lock(m1, m2) //m1,m2同时上锁
std::lock_guard<std::mutex> lguard1(m1, std::adopt_lock); //用lock_guard自动unlock锁
std::lock_guard<std::mutex> lguard2(m2, std::adopt_lock);
... //访问共享变量
//不再需要unlock锁m1和m2了
3)
std::mutex m1, m2;
std::lock(m1, m2) //m1,m2同时上锁
std::unique_guard<std::mutex> uguard1(m1, std::adopt_lock); //用lock_guard自动unlock锁
std::unique_guard<std::mutex> uguard2(m2, std::adopt_lock);
... //访问共享变量
//不再需要unlock锁m1和m2了
5. std::timed_mutex 带超时功能的独占互斥量
类似函数std::recursive_timed_mutex 允许同一个线程多次获取同一个互斥量
头文件#include <mutex>
- try_lock_for()函数:等待一段时间。如果拿到锁或者等待超时,就往下执行。
- try_lock_until()函数:参数是一个未来时间点,在未来一段时间内如果拿到锁就走下来;如果时间到了没有拿到锁,程序也走下来。
比如:
1)
std::timed_mutex m;
std::chrono::millisecond timeout(100);
if(m.try_lock_for(timeout)){ //程序等待100毫秒尝试拿锁,如果拿到锁执行if,否则else
... //拿到锁,执行互斥内容
m.unlock();
}
else{
... //没有拿到锁
}
2)
std::timed_mutex m;
std::chrono::millisecond timeout(100);
if(m.try_lock_until(std::chrono::steady_clock::now() + timeout)){ //程序从当前时间开始经过100毫秒时间,如果拿到锁,执行if,否则执行else
... //执行互斥内容
m.unlock();
}
else{
... //没有拿到锁
}
以上内容,详情查看文档