C++ —— 线程同步(互斥锁)
C++ —— 线程同步(互斥锁)
- 线程同步
- 互斥锁(互斥量)
- 测试代码
- mutex互斥锁
线程同步
线程同步
:多线程协同工作,协商如何使用共享资源。
C++11
线程同步包含三部分内容:
互斥锁
(互斥量)- 条件变量
- 生产/消费者模型
互斥锁(互斥量)
只有加锁
和解锁
两种状态,确保同一时间
只有一个线程
访问共享资源。
访问共享资源之前加锁
,加锁成功
,访问
资源,访问完成
,解锁
释放。
若某线程持有锁
,其他线程形成等待队列
。
C++11
提供了4
种互斥锁:
mutex
:互斥锁(最常用)timed_mutex
:带超时机制的互斥锁recursive_mutex
:递归互斥锁recursive_timed_mutex
:带超时机制的递归互斥锁
测试代码
#include <iostream>
#include <thread>
using namespace std;
void func (int n, const string& s) {
for (int i = 1; i <= 10; i++) {
cout << "No." << i << ", n = " << n << ", s = " << s << endl;
this_thread::sleep_for(chrono::seconds(1));
}
}
a
int main () {
thread t1(func, 1, "t1");
thread t2(func, 2, "t2");
thread t3(func, 3, "t3");
thread t4(func, 4, "t4");
thread t5(func, 5, "t5");
thread t6(func, 6, "t6");
t1.join();
t2.join();
t3.join();
t4.join();
t5.join();
t6.join();
return 0;
}
cout
属于全局对象,若多线程都用它向屏幕输出文字,会出乱子。线程越多,越容易乱。
mutex互斥锁
使用互斥锁
给cout
加锁,代码如下:
#include <iostream>
#include <thread>
#include <mutex> // 使用互斥锁需要包含的头文件
using namespace std;
mutex mtx; // 创建互斥锁对象,用于保护共享资源cout对象。
void func (int n, const string& s) {
for (int i = 1; i <= 10; i++) {
// 每次调用cout对象之前,申请加锁
mtx.lock();
cout << "No." << i << ", n = " << n << ", s = " << s << endl;
// 用完了就解锁
mtx.unlock();
this_thread::sleep_for(chrono::seconds(1));
}
}
int main () {
// 代码不变...
}
再看一段示例代码:
#include <iostream>
#include <chrono> // 时间相关操作的头文件
#include <thread> // 线程相关操作的头文件
#include <mutex> // 互斥锁的头文件
using namespace std;
int a = 0;
mutex mtx; // 创建互斥锁对象,用于保护共享资源a变量。
void func () {
for (int i = 0; i < 1000000; ++i) {
mtx.lock();
a++;
mtx.unlock();
}
}
int main () {
auto start = chrono::steady_clock::now();
thread t1(func);
thread t2(func);
t1.join();
t2.join();
auto end = chrono::steady_clock::now();
cout << "time = " << chrono::duration_cast<chrono::milliseconds>(end - start).count() << "ms" << endl;
cout << "a = " << a << endl;
return 0;
}
运行结果:
time = 101ms
a = 2000000
在代码中添加一些打印信息,能更清楚的观察到:两个线程申请加锁,只有一个成功,另外一个线程等待,直到第一个线程解锁后第二个线程才能加锁。
#include <iostream>
#include <chrono> // 时间相关操作的头文件
#include <thread> // 线程相关操作的头文件
#include <mutex> // 互斥锁的头文件
using namespace std;
int a = 0;
mutex mtx;
void func () {
for (int i = 0; i < 1000000; ++i) {
cout << "thread id: " << this_thread::get_id() << ", 申请加锁" << endl;
mtx.lock();
cout << "thread id: " << this_thread::get_id() << ", 加锁成功" << endl;
a++;
this_thread::sleep_for(chrono::seconds(5));
mtx.unlock();
cout << "thread id: " << this_thread::get_id() << ", 解锁" << endl;
this_thread::sleep_for(chrono::seconds(1));
}
}
int main () {
thread t1(func);
thread t2(func);
t1.join();
t2.join();
cout << "a = " << a << endl;
return 0;
}
运行结果:
thread id: 139727756003072, 申请加锁
thread id: 139727756003072, 加锁成功
thread id: 139727747610368, 申请加锁
thread id: 139727756003072, 解锁
thread id: 139727747610368, 加锁成功
thread id: 139727756003072, 申请加锁
thread id: 139727747610368, 解锁
…
感谢浏览