1.std::mutex类

1.构造函数,std::mutex不允许拷贝构造,也不允许 move 拷贝,最初产生的 mutex 对象是处于 unlocked 状态的。
2.lock(),调用线程将锁住该互斥量。线程调用该函数会发生下面 3 种情况:①如果该互斥量当前没有被锁住,则调用线程将该互斥量锁住,直到调用 unlock之前,该线程一直拥有该锁。②如果当前互斥量被其他线程锁住,则当前的调用线程被阻塞住。③如果当前互斥量被当前调用线程锁住,则会产生死锁(deadlock)。
3.unlock(), 解锁,释放对互斥量的所有权
4.unlock 和lock配套使用
5.必须在每个离开函数的路径上调用unlock。

2.std::lock_guard类

std::lock_guard使用起来比较简单,除了构造函数外没有其他成员函数。
优势在于不用配对使用

#include <thread>
#include <iostream>
#include <mutex>
std::mutex some_mutex;
void add()
{
    std::lock_guard<std::mutex> guard(some_mutex);
}

3.使用std::unique_lock灵活锁定

为了实现锁粒度,std::lock_guard就显得不够灵活,一个例子:

#include <thread>
#include <iostream>
#include <mutex>
std::mutex some_mutex;
void add()
{
    {  //这边的括号是为了作用域,以便自动解锁
        std::lock_guard<std::mutex> guard(some_mutex);
        //do something_1
    }
    //do something_2

    {
        std::lock_guard<std::mutex> guard(some_mutex);
        //do something_3
    }
}

使用unique_lock

void add()
{
    std::unique_lock<std::mutex> lock_1(some_mutex,std::defer_lock);//保留互斥元为未锁定
    std::lock(lock_1); //互斥元在这里锁定
    // do something_1
    std::unlock(lock_1);
    //do something_2
    std::lock(lock_1);
    // do something_3
    std::unlock(lock_1);
}

4.使用相同的顺序锁定互斥元来避免死锁

使用std::lock函数

std::mutex m1,m2;
void mutexer()
{
    std::lock(m1, m2); //锁定这两个互斥元

    //构建两个实例,告知该互斥元对象已被锁定,只是获取所有权,并不试图锁定互斥元
    std::lock_guard<std::mutex> lock_1(m1, std::adopt_lock);
    std::lock_guard<std::mutex> lock_2(m2, std::adopt_lock);
}
01-21 23:30