Mutex 线程锁

避免C++多线程对同一数据写入和读取,产生的错误

1. 锁 std::mutex

1.创建std::mutex mtx 对象 用mtx.lock()上锁 mtx.unlock() 解锁

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
#include <iostream>
#include <thread>
#include <vector>
#include <mutex>
#include <chrono>
#include <stdexcept>

int counter = 0;
std::mutex mtx; // 保护counter

void increase(int time) {
for (int i = 0; i < time; i++) {
mtx.lock();
// 当前线程休眠1毫秒
std::this_thread::sleep_for(std::chrono::milliseconds(1));
counter++;
mtx.unlock();
}
}

int main(int argc, char** argv) {
std::thread t1(increase, 10000);
std::thread t2(increase, 10000);
t1.join();
t2.join();
std::cout << "counter:" << counter << std::endl;
return 0;
}

使用std::mutex 有个问题.如果一个线程里中有有异常,返回的异常的时候没有 解锁,导致其他线程的锁死。所以引入:std::lock_guard

2. std::lock_guard

声明lock_guard 后自动进行lock() 上锁,离开作用域后会自动unlock() 解锁

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
32
33
34
35
36
37
38
39
40
41
42
#include <iostream>
#include <thread>
#include <vector>
#include <mutex>
#include <chrono>
#include <stdexcept>

int counter = 0;
std::mutex mtx; // 保护counter

void increase_proxy(int time, int id) {
for (int i = 0; i < time; i++) {
// std::lock_guard对象构造时,自动调用mtx.lock()进行上锁
// std::lock_guard对象析构时,自动调用mtx.unlock()释放锁
std::lock_guard<std::mutex> lk(mtx);
// 线程1上锁成功后,抛出异常:未释放锁
if (id == 1) {
throw std::runtime_error("throw excption....");
}
// 当前线程休眠1毫秒
std::this_thread::sleep_for(std::chrono::milliseconds(1));
counter++;
}
}

void increase(int time, int id) {
try {
increase_proxy(time, id);
}
catch (const std::exception& e){
std::cout << "id:" << id << ", " << e.what() << std::endl;
}
}

int main(int argc, char** argv) {
std::thread t1(increase, 10000, 1);
std::thread t2(increase, 10000, 2);
t1.join();
t2.join();
std::cout << "counter:" << counter << std::endl;
return 0;
}

如果想在线程里执行多次的lock() 和unlock() 就需要引入std::unique_lock,离开作用域自动解锁,支持条件判断,就需要使用std::unique_lock

3. std::unique_lock

1.普通用法

1
2
3
4
5
6
7
8
9
10
11
12
13
std::mutex mtx;

void func() {
std::unique_lock<std::mutex> lock(mtx, std::defer_lock); // 不立即加锁
// 其他代码
lock.lock(); // 手动加锁
// 其他代码
lock.unlcok() //手动解锁
// 其他代码
lock.lock() //手动加锁

}

2.延迟加锁

1
2
3
4
5
6
7
8
9
std::mutex mtx;

void func() {
std::unique_lock<std::mutex> lock(mtx, std::defer_lock); // 不立即加锁
// 其他代码
lock.lock(); // 手动加锁
// ...
}

3.加锁判断

1
2
3
4
5
6
7
8
9
10
std::mutex mtx;
std::condition_variable cv;
bool ready = false;

void wait_thread() {
std::unique_lock<std::mutex> lock(mtx);
cv.wait(lock, []{ return ready; }); // 自动释放+重新加锁
// 继续执行
}

4. std::shared_lock() 共享锁多个线程共享 用在读取数据