【操作系统】线程——C++11

目录

创建线程

多线程多次运算,结果错误

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;因为两个线程访问了公共资源(临界资源)。

解决:

1. 信号量

#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();
	}
}

上面这种形况也会形成死锁。

解决:

1.RALL编程思想

资源获取即初始化”(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构造函数中加锁,析构函数中解锁。

2. 加锁顺序一致

3. lock函数

std::lock(mtx1, mtx2)

2. 原子变量

#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));

由于生产者和消费者的速度不确定,所以会出现资源浪费。

解决:

1. 引入条件变量

#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);
}

2. 信号量需要c++20

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) 

你可能感兴趣的:(c++,开发语言)