1. 使用互斥器进行线程同步
#include <iostream>
#include <thread>
using namespace std;
const int n = 5;
void func(char ch)
{
for (int i = 0; i < n; i++)
{
cout << ch;
}
cout << endl;
}
int main()
{
std::thread thrd[5];
for (int i = 0; i < 5; i++)
{
// 让线程分别打印出 “aaaaa”、“bbbbb” ....
thrd[i] = std::thread(func, i + 'a');
}
for (auto& t : thrd) t.join();
return 0;
}
运行结果:
在多线程中,vs的调试控制台也是一个临界资源,各个线程将执行结果向屏幕输出的过程中可能会被其他线程抢占资源,从而出现如图二的情况。(a只打印了3个就被其他线程抢占了,直到其他线程打印完才将剩余的数据打印在屏幕上)
1.1 mutex互斥器
https://zh.cppreference.com/w/cpp/header/mutex
mutex 类是能用于保护共享数据免受从多个线程同时访问的同步原语。
#include <iostream>
#include <thread>
#include <mutex>
using namespace std;
const int n = 5;
std::mutex g_mtx; // 定义互斥器
void func(char ch)
{
g_mtx.lock(); // 加锁
for (int i = 0; i < n; i++)
{
cout << ch;
}
cout << endl;
g_mtx.unlock(); // 解锁
}
int main()
{
std::thread thrd[5];
for (int i = 0; i < 5; i++)
{
// 让线程分别打印出 “aaaaa”、“bbbbb” ....
thrd[i] = std::thread(func, i + 'a');
}
for (auto& t : thrd) t.join();
return 0;
}
运行结果:
注意:该方式只能保证每个线程在访问临界资源(屏幕打印)时,不被其他线程侵占,而不能保证各个线程的执行顺序(即,先打印“aaaaa”,在打印“bbbbb” …)。
1.2 std::lock_guard(保护)
#include <iostream>
#include <thread>
#include <mutex>
using namespace std;
const int n = 5;
std::mutex g_mtx; // 定义互斥器
void func(char ch)
{
//g_mtx.lock(); // 加锁
std::lock_guard<std::mutex> lock(g_mtx);
for (int i = 0; i < n; i++)
{
cout << ch;
}
cout << endl;
//g_mtx.unlock(); // 解锁
// g_mtx 在锁离开作用域时自动释放
}
int main()
{
std::thread thrd[5];
for (int i = 0; i < 5; i++)
{
// 让线程分别打印出 “aaaaa”、“bbbbb” ....
thrd[i] = std::thread(func, i + 'a');
}
for (auto& t : thrd) t.join();
return 0;
}
除此之外mutex还有很多方法,具体可参考https://zh.cppreference.com/w/cpp/header/mutex
有关mutex类参考:https://blog.csdn.net/faihung/article/details/88411839
Mutex 系列类(四种)
-
std::mutex,最基本的 Mutex 类。
-
std::recursive_mutex,递归 Mutex 类。
-
std::time_mutex,定时 Mutex 类。
-
std::recursive_timed_mutex,定时递归 Mutex 类。
Lock 类(两种) -
std::lock_guard,与 Mutex RAII 相关,方便线程对互斥量上锁。
-
std::unique_lock,与 Mutex RAII 相关,方便线程对互斥量上锁,但提供了更好的上锁和解锁控制。