目录
创建线程
多线程多次运算,结果错误
1. 信号量
1.RALL编程思想
2. 加锁顺序一致
3. lock函数
2. 原子变量
消费者生产者问题
1. 引入条件变量
虚假唤醒
2. 信号量需要c++20
来源:
#include
#include //c++11
//伪多线程 单核cpu
//多线程
void func(int a){
while(true){
std::cout<<"Hello word\n";
//休眠50 微秒 milliseconds毫秒
std::this_thread::sleep_for(std::chrono::microseconds(50));
}
}
int main(){
int a=0;
std::thread thread1(func,a);
//thread1.join();//阻塞,等thread1运行完,释放
//thread1.detach();//将thread1与主线程分离开,不会阻塞主线程
//主线程无法获取子线程的执行结果
//小心指针类变量,需要释放
//while(true);
return 0;
}
报错:terminate called without an active exception
原因:如果没有打开主函数里的三句注释中的任一一句,主程序会在创造并开启thread1线程后,直接走到return 0。此时,主线程结束,但thread1子线程还没有结束。
#include
#include
#include //互斥量
std::mutex mtx;
int globalVariable = 0;
void task1(){
for(int i=0;i<1000000;i++){
globalVariable++;
globalVariable--;
}
}
void task2(){
for(int i=0;i<1000000;i++){
globalVariable++;
globalVariable--;
}
}
int main(){
std::thread t1(task1);
std::thread t2(task2);
t1.join();
t2.join();
std::cout<
当经过多次运算(1000000次)后,globalVariable的值并不为0;因为两个线程访问了公共资源(临界资源)。
解决:
#include
#include
#include //信号量
std::mutex mtx;
int globalVariable = 0;
void task1(){
for(int i=0;i<1000000;i++){
mtx.lock();
globalVariable++;
globalVariable--;
mtx.unlock();
}
}
void task2(){
for(int i=0;i<1000000;i++){
mtx.lock();
globalVariable++;
globalVariable--;
mtx.unlock();
}
}
int main(){
std::thread t1(task1);
std::thread t2(task2);
t1.join();
t2.join();
std::cout<
两个锁之间的代码块称为临界资源
当临界资源直接退出该线程时,会导致该互斥量没有被释放,形成死锁。如
callFUNC(); throw;
或
if(1==1) {
return ;
}
void task1(){
for(int i=0;i<1000000;i++){
mtx1.lock();
mtx2.lock();
globalVariable++;
globalVariable--;
mtx1.unlock();
mtx2.unlock();
}
}
void task2(){
for(int i=0;i<1000000;i++){
mtx2.lock();
mtx1.lock();
globalVariable++;
globalVariable--;
mtx2.unlock();
mtx1.unlock();
}
}
上面这种形况也会形成死锁。
解决:
资源获取即初始化”(Resource Aquisition Is Initialization)
利用C++对象生命周期的概念来控制程序的资源。
void task1(){
for(int i=0;i<1000000;i++){
std::lock_guard lock(mtx1);
// std::lock_guard lock(mtx2);
std::unique_lock lock(mtx1); //更灵活,有更多的函数
globalVariable++;
globalVariable--;
}
}
大致相当于 lock_guard构造函数中加锁,析构函数中解锁。
std::lock(mtx1, mtx2)
#include
std::atomic globalVariable = 0;
#include
#include
#include
#include
#include
std::mutex mtx;
std::deque q;
// producer
void task1(){
int i=0;
while(true){
std::unique_lock lock(mtx);
q.push_back(i);
if(i<9999999){
i++;
}else{
i=0;
}
}
}
//consumer
void task2(){
int data=0;
while(true){
std::unique_lock lock(mtx);
if(!q.empty()){
data = q.front();
q.pop_front();
std::cout<<"get:"<
如果让程序等待std::this_thread::sleep_for(std::chrono::microseconds(50));
由于生产者和消费者的速度不确定,所以会出现资源浪费。
解决:
#include
#include
#include
#include
#include
std::mutex mtx;
std::deque q;
std::condition_variable cv;
// producer
void task1(){
int i=0;
while(true){
std::unique_lock lock(mtx);//互斥
q.push_back(i);
cv.notify_one();//生产者生产 一个 产品,释放条件变量,从而唤醒 一个 消费者
//cv.notify_all();
if(i<9999999){
i++;
}else{
i=0;
}
}
}
//consumer
void task2(){
int data=0;
while(true){
std::unique_lock lock(mtx);//加互斥量
if(q.empty()){ //如果 没有产品 阻塞消费者进程
cv.wait(lock);//函数作用:阻塞进程,并释放lock(mtx.unlock())
}
if(!q.empty()){
data = q.front();
q.pop_front();
std::cout<<"get:"<
当出现两个及以上消费者时,生产者生产一个产品和唤醒第二个消费者之间的时刻,恰好,第一个消费者在wait的判断,从而两个消费者消费了一个产品。
从而形成
解决:
将wait前的if换成while
while(q.empty()){
cv.wati(lock);
}
devc++不支持。。。。
就是binary sem相当于counting sem中模板参数为1的情况,把这个情况单拿出来叫binary sem
(17条消息) terminate called without an active exception错误分析_庸人岳的博客-CSDN博客
[C++ 多线程并发 基础入门教程] 1.2 互斥量(mutex), 原子变量(atomic)_哔哩哔哩_bilibili
技术点:RALL编程思想 - 简书 (jianshu.com)