文章目录
子线程开启、互斥变量、条件变量
std::thread 用于开启一个线程。
作用
std::thread 用于开启一个子线程。
举例:
void threadfunc()
{
printf("sub thread\n");
}
int main(int argc, const char * argv[])
{
std::thread th(threadfunc);
//th.join();
th.detach();
return 0;
}
解释
上面的代码中 std::thread th(threadfunc) 开启了一个子线程。子线程的主函数是 threadfunc().
线程开启后,必须 join() 或者 detach() 否则会出现 th 这个变量退出作用域,被析构时,会报异常。
join() 的含义是,主线程必须等到这个子线程执行结束,才能继续。子线程结束之前,主线程会卡死在 th.join() 这一行。
detach() 的含义是,此线程与 th 这个变量毫无关联。这时,如果 th 变量析构后,不影响子线程的执行。并且 detach() 之后,主线程、子线程交替执行,两个线程之间没有先后关系。
std::mutex 互斥锁
作用
防止不同线程间的代码在不同线程间做不安全的切换
作用分析:mutex mtx,会定义一个变量mtx,如果mtx上锁了,即lock(),则多个线程在同一时刻仅上锁线程可以调用mtx,别的线程不能调用,只能在mtx处停止,等待mtx解锁。
举例
例如,一个子线一直往数组 std::vector arr 里插入元素,主线程一直从数组里删除元素。两个线程同时涉及修改 arr 变量。为了防止线程不同步,两个线程在各自操作 arr变量前,需要声明一个 std::mutex 变量,用 lock() unlock() 把关键的代码包围起来。
#include <stdio.h>
#include <thread>
#include <mutex>
#include <vector>
std::mutex mtx;
std::vector<int> arr;
void threadfunc()
{
while(true)
{
mtx.lock();
arr.push_back(3);
mtx.unlock();
}
}
int main(int argc, const char * argv[])
{
std::thread th(threadfunc);
th.detach();
while(true)
{
mtx.lock();
if(arr.size() > 0) {
arr.erase(arr.begin());
}
mtx.unlock();
}
return 0;
}
解释
mutex 的 lock() 函数是会阻塞线程的。如果在 lock() 时,该 mutex 已经被其他线程调用了 lock,则此时会将线程卡死在 lock() 函数调用的位置,直到其他线程 unlock() 释放了 mutex ,这个线程才能继续执行。
条件std::condition_variable con
作用
唤醒作用于process线程中的获取观测值数据的函数
- 场景:线程1正在执行锁,线程2正在等待线程1解锁。那么线程2可以开启等待wait,线程1在解锁时可以调佣命令唤醒线程2,即:
- 线程1:当该线程执行完程序并unlock后,可以开启 con.notify_one(),用来唤醒wait()线程。
- 线程2:在等待时,线程2应该先解锁mutex,然后wait(),在被唤醒之后,wait()结束,然后使用mutex的lock进行上锁,然后执行程序,执行完毕后,进行解锁。
- 首先使用std::unique_lock管理互斥锁,保证在wait()时,mutex的锁是解锁状态
- 然后,调用wait()函数等待被唤醒。该函数可以添加λ表示,当返回true时才解锁。
- 唤醒后由于unique_lock在管理互斥锁,所以可以自动上锁。
- 最后就可以执行代码段,执行完毕之后,需手动调用互斥锁管理器中的unlock进行解锁。
举例
#include <iostream>
#include <deque>
#include <thread>
#include <mutex>
#include <condition_variable>
std::deque<int> q; //双端队列标准容器全局变量
std::mutex mu; //互斥锁全局变量
std::condition_variable cond; //全局条件变量
//生产者,往队列放入数据
void function_1() {
int count = 10;
while (count > 0) {
// 对互斥量mu上锁
mu.lock();
q.push_front(count); //数据入队锁保护
// 对互斥量mu解锁
mu.unlock();
// 向一个等待线程发出“条件已满足”的通知
cond.notify_one();
std::this_thread::sleep_for(std::chrono::seconds(1)); //延时1秒
count--;
}
}
//消费者,从队列提取数据
void function_2() {
int data = 0;
while ( data != 1) {
// 定义一个互斥锁管理器
std::unique_lock<std::mutex> aa(mu);
// wait()表示解锁互斥量并陷入休眠以等待通知被唤醒,被唤醒后自动加锁以保护共享数据
// wait(),前部分是等待被唤醒,后面是λ表达式,判断队列是否为空,都满足才解除休眠
cond.wait(aa, []{return !q.empty();});
data = q.back();
q.pop_back(); //数据出队
// 使用unique_locd进行 解锁
aa.unlock();
std::cout << "t2 got a value from t1: " << data << std::endl;
}
}
int main() {
std::thread t1(function_1);
std::thread t2(function_2);
t1.join();
t2.join();
getchar();
return 0;
}