c++多线程
一:创建线程(thread)
https://blog.csdn.net/qq_46470984/article/details/125334459?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522167619985416800182782048%2522%252C%2522scm%2522%253A%252220140713.130102334.pc%255Fblog.%2522%257D&request_id=167619985416800182782048&biz_id=0&spm=1018.2226.3001.4450
ps:线程thread类不能直接返回函数的返回值,所以会在函数的参数中增加一个参数来保存结果。
二: 互斥量(mutex), 原子变量(atomic)
当多个线程同时对同一数据进行操作时造成线程不安全,无法得到预期的结果。所以要对数据进行保护。简单理解就是:在调用数据之前对数据进行上锁,使用完数据后再对数据进行解锁。这样当数据被使用时,由于数据提前被上锁则其他线程无法访问,避免了多个线程同时处理数据产生的问题。
https://blog.csdn.net/qq_46470984/article/details/125334818?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522167619985416800182782048%2522%252C%2522scm%2522%253A%252220140713.130102334.pc%255Fblog.%2522%257D&request_id=167619985416800182782048&biz_id=0&spm=1018.2226.3001.4450
lock_gard和unique_lock只在离开作用域时解锁,在下面代码中将一直执行到for循环结束。
unique_lock可以通过lock.unlock()设置解锁位置。
#include <iostream>
#include <thread>
#include <mutex>
#include <atomic>
std::mutex mtx;
int globalVariable = 0;
//std::atomic<int> globalVariable = 0;
void task1()
{
for (int i = 0; i < 1000; i++)
{
std::lock_guard<std::mutex> lock(mtx);
//mtx.lock();
globalVariable++;
//mtx.unlock();
std::cout << "task1: globalVariable is " << globalVariable << std::endl;
}
}
void task2()
{
for (int i = 0; i < 1000; i++)
{
std::unique_lock<std::mutex> lock(mtx);
globalVariable--;
//unique_lock可以通过lock.unlock()设置解锁位置
lock.unlock();
std::cout << "task2: globalVariable is " << globalVariable << std::endl;
}
}
int main()
{
std::thread t1(task1);
std::thread t2(task2);
t1.join();
t2.join();
std::cout << "current value is " << globalVariable;
}
三:C++ 多线程并发 基础入门教程 1.3 条件变量(condition_variable), 信号量(semaphore)
1.条件变量(condition_variable)
https://blog.csdn.net/qq_46470984/article/details/125340274?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522167619985416800182782048%2522%252C%2522scm%2522%253A%252220140713.130102334.pc%255Fblog.%2522%257D&request_id=167619985416800182782048&biz_id=0&spm=1018.2226.3001.4450
1)引出问题:while循环很占CPU
使用std::this_thread::sleep_for会缓解循环,但是延迟的时间不好设定,影响程序运行。使用条件变量(condition_variable)可以使程序平时处于休眠(wait)的状态,在满足某一条件时再被唤醒(notify)开始运行,避免资源的占用。
2)使用条件变量(condition_variable)引入两个消费者线程同时对生产者线程操作时,可能会出现虚假唤醒。即当某个条件并没有被实际满足时,线程依旧被唤醒。
例子:消费者一被唤醒,从队列中将数据取出;这时生产者又将新的数据压入队列,新唤醒消费者二线程;新的数据被之前的消费者一线程先推出队列,这时消费者二就找不到数据,导致虚假唤醒。
解决办法:可以使用while循环来判断队列是否为空,对队列一直进行监控,这也可以解决虚假唤醒。
2.信号量(semaphore)
不同于mutex可以允许同一个资源被多个线程访问。
调用acquire时使得信号量semaphore自身的计数器减一,变为负数后acquire阻塞。直到调用release时使计数器增加。
binary_semaphore 条件信号量计数器只有0、1两个值,release默认为1,也只能为1。它是counting_semaphore 计数信号量的特殊情况,相当于:std::binary_semaphore = std::counting_semaphore<1>
四:C++ 多线程并发 基础入门教程 1.4 promise future
https://blog.csdn.net/qq_46470984/article/details/125343241?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522167619985416800182782048%2522%252C%2522scm%2522%253A%252220140713.130102334.pc%255Fblog.%2522%257D&request_id=167619985416800182782048&biz_id=0&spm=1018.2226.3001.4450
promise和future为模板类,promise提前承诺会在未来传递给future一个数值,future接收到数值后再传递给程序。
一、常规操作的大致流程如下:线程承诺给主函数一个数值
1)首先声明模板类promise对象p,然后再声明模板类future对象f。promise和future通过p.get_future()联系在一起。
2)通过引用将p传递给未来产生数据的线程,一般也就是线程的输出。3)通过set_value函数获得承诺给future的数据。
4)f通过get函数读取到p传递过来的数据。get函数会使程序一直阻塞,直到promise完成set_value的操作。
二、反向操作:主线程承诺给线程一个数值。
1)同一
2)通过引用将f传递给未来接收数据的线程,一般也就是线程的输入。
3)在后面的主程序中获得传递给线程的数值后,通过set_value函数获得承诺给future的数据。
4)子线程中,f通过get函数读取到p传递过来的数据。get函数会使程序一直阻塞,直到promise完成set_value的操作。
五:C++ 多线程并发 基础入门教程 1.5 std::packaged_task std::async
https://blog.csdn.net/qq_46470984/article/details/125343947?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522167619985416800182782048%2522%252C%2522scm%2522%253A%252220140713.130102334.pc%255Fblog.%2522%257D&request_id=167619985416800182782048&biz_id=0&spm=1018.2226.3001.4450
视频地址:https://space.bilibili.com/25594943/channel/seriesdetail?sid=2520972