(备忘录)
一、互斥锁
#inclide < mutex >
std::mutex m; m.lock(), m.unlock(),try_lock().
try_lock() 与 lock()的不同在于,try_lock() 在获取不到锁的时候不会阻塞,只会返回false表示拿不到锁。
std::lock_guard<std::mutex> gm;
std::unique_lock<std::mutex> um;
mutex::scoped_lock 是 unique_lock的 typedef
lock_guard 和 unique_lock 都遵循RAII(资源访问即初始化:访问互斥资源的时候只需要初始化后就可以往下走,不用考虑释放锁)原则,但unique_lock 比 lock_guard 灵活,unique_lock 还额外提供了lock和unlock操作。unique_lock 和 lock_guard 都不可以拷贝复制,unique_lock 可move().
std::recursive_mutex:与mutex 的不同在于recursive_mutex可以在同一个线程中递归使用或说是嵌套使用,即里里外外每一层都可以使用,只要保证每一层的lock和unlock成对出现就行。
std::time_mutex:与mutex相比,多了2个时间相关的函数:try_lock_for(时间段) 和 try_lock_until(时间点) ,相当于mutex的try_lock(),但比try_lock()多个了个时间,try_lock()是拿不到锁直接返回,而try_lock_for(时间段) 和 try_lock_until(时间点) 是在传入的时间内拿不到锁则阻塞,超时后返回false。try_lock()相当于try_lock_for(0)。
二、条件锁
#include < condition_variable >
std::condition_variable(只和std::mutex一起工作) 和 std::condition_variable_any(符合类似互斥元的最低标准的任何东西一起工作)
条件变量解决的问题:在线程循环中等待时通过wait和notify来及时处理事件,如果没有这个机制的话wait的地方需要忙等或者sleep固定时长来不断的检测条件浪费CPU和浪费时间。
条件变量wait 需要传入unique_lock和一个返回布尔值的函数对象,为什么此处会需要这2个参数?首先线程要在wait出阻塞,那就需要在阻塞之后释放锁,这样其他使用该锁的地方才能继续工作,所以传入unique_lock在wait内部unlock。当notify之后wait还是被唤醒(中断后继续),使用unique_lock进行lock,然后继续执行。第2个参数是个函数,用来判断被唤醒之后是要直接返回还是继续往下走,true往下走,false直接返回,这样方便判断队列空不空,空的话就没必要继续往下走了。
std::mutex mut;
std::queue<data_chunk> data_queue;;
std::condition_variable data_cond;
std::lock_guard<std::mutex> lk(mut);
data_queue.push(data);
data_cond.notify_one();
void data_processing_thread()
{
while(true)
{
std::unique_lock<std::mutex> lk(mut); //这里使用unique_lock是为了后面方便解锁
data_cond.wait(lk,{[]return !data_queue.empty();});
data_chunk data=data_queue.front();
data_queue.pop();
lk.unlock();
process(data);
if(is_last_chunk(data))
break;
}
}
三、自旋锁
一个忙等的锁(busy-waiting),不断循环的去获取锁。
自旋锁是Linux内核里最常用的锁之一。
自旋锁的逻辑是,用自旋锁保护的临界区要足够小,而且临界区内是不能休眠的。所以当自旋锁加锁失败时,说明有其它的临界区正在执行中。由于自旋锁的临界区足够小且不会休眠,所以我们可以自旋忙等待其它临界区的退出,没必要去休眠,因为休眠要做一大堆操作。而忙等待的话,对方很快就会退出临界区,我们就可以很快地获得自旋锁了。
四、读写锁
C++ 17里已经引进了读写锁 std::shared_mutex , 其lock()即以写方式加锁, 其lock_shared()即以读方式加锁,但C++11还没有引入,只能使用boost里面的。
这是boost里面的锁,需要引入boost
#include <boost/thread/shared_mutex.cpp>
boost::shared_lock