互斥

c++通过std::mutex实现锁机制,确保多线程下只有一个进入临界区

1
2
3
4
#include <mutex>
std::mutex mtx;
mtx.lock();
mtx.unlock();

当一个函数内需要获取多个锁时,可以采用lock同时加锁,固定加锁的顺序避免死锁

1
2
3
4
5
6
7
8
9
lock(m1, m2);
lock_guard<mutex> g1(m1, adopt_lock);
lock_guard<mutex> g2(m2, adopt_lock);
/*等价于
unique_lock<mutex> l1(n1, defer_lock);
unique_lock<mutex> l2(n2, defer_lock);
lock(m1,m2)
*/
//或者等价于 scoped_lock s1(m1,m2);

层级锁

自定义锁添加权重来保证每次加锁顺序和解锁顺序,数值越大权重越高,核心static thread_local unsigned cur这个字段,保证了线程中多把锁存在时

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
class hmutex {
public:
hmutex(unsigned val):cur(val),pre(0){}
hmutex(hmutex const&) = delete;
hmutex& operator=(hmutex const&) = delete;

void lock(){
if(cur <= val) std::logic_error("faild");
mtx.lock();
pre=cur,cur=val;
}
void unlock(){
if(cur != val) std::logic_error("faild");
cur = pre;
mtx.unlock();
}
private:
std::mutex mtx;
unsigned const val;
unsigned pre;
static thread_local unsigned cur;
};

const unsigned HIGH = 500;
cosnt unsigned MID = 300;
const unsigned LOW = 100;

hmutx h1(HIGH);
hmutex h2(MID);
hmutex h3(LOW)

share_mutex

C++17新增了共享锁用来访问共享数据,实现读写锁,C++14提供share_timed_mutex,不同的是在获取锁时提供了超时机制

lock(), try_lock()

lock_shared(), try_lock_shared()

1
2
3
std::shared_mutex mtx;
std::shared_lock<std::shared_mutex> sl(mtx);
std::lock_guard<std::shared_mutex> gl(mtx);

RAII锁

lock_guard

构造析构时自动加锁解锁,因此当中途return或退出时会自动释放锁

1
2
3
{
std::lock_guard<std::mutex> lock(mtx);
}

c++容器不是线程安全的,因此每次操作都需要加锁

unique_lock

比lock_guard更加灵活,可以手动解锁,服务细粒度场景

支持同条件变量一起使用,一旦mutex被unique_lock管理就不能通过mutex加锁解锁

使用owns_lock()判断有无获取锁

可以延迟加锁std::unique_lock<std::mutex>(mtx,std::defer_lock)

mutex不支持移动和拷贝,但可以通过unique_lock进行转移

scope_lock

c++17新特性,可对多个互斥量同时加锁

1
2
3
{
std::scople_lock lock(mtx1, mtx2);
}

shared_lock

到来c++14,17才有了共享锁,lock获取互斥锁,lock_shared获取共享锁

shared_mutex与shared_timed_mutex异同:

  • lock两者都会阻塞直到获取锁,lock_shared则提供超时机制,