C++异步(1)

什么是异步?

异步就是多个线程是同时执行的,与之相对的就是线程同步,二者都应用在并发的场景上。

异步的特点

异步执行的任务无需等待其他任务完成,其本身是通过非阻塞的方式执行的,不依赖前驱任务,通常用于IO密集型场景。

非阻塞:线程不会被其他线程阻塞;

回调或事件驱动:

1、可以通过最直接采用策略执行回调函数,自动创建和管理线程;

2、还可以通过primise收到那个执行线程设置future的异步结果;

未来类--future

future简单来说就是存储线程结果的一个模版类,我们可以通过其get方法获取其异步编程结果的值;

async策略

执行策略:launch::async代表的是立刻在当前线程处执行异步回调函数;

cpp 复制代码
//执行线程回调函数
double func(){
    cout<<"我是线程回调函数"<<endl; 
    return 6.6;
}

void testfuture(){
    future<double> ret=async(launch::async,func);//立即执行的策略
    cout<<"开始睡眠"<<endl;
    sleep(2);
    auto res=ret.get();
    cout<<"future:"<<res<<endl; 
}

其中ret接收的就是异步线程回调函数的返回值;

deferred策略

该执行策略代表的是延迟执行,也就是主线程执行到async函数时不会立刻触发执行异步回调函数,而是在后续调用future的get方法时才会触发执行回调函数;

cpp 复制代码
#pragma once 
#include <future>
#include <iostream>
#include <unistd.h>
using namespace std; 



//执行线程回调函数
double func(){
    cout<<"我是线程回调函数"<<endl; 
    return 6.6;
}


void testfuture2(){
    future<double>ret=async(launch::deferred,func);//延迟执行策略
    cout<<"开始睡眠"<<endl;
    sleep(2);
    auto res=ret.get();

    cout<<"future:"<<res<<endl; 
}

这段程序的执行结果就是先打印"开始睡眠",然后睡眠2s,执行到get处,才执行回调函数,打印"我是线程回调函数",返回res获取返回值6.6,最后打印"future:6.6";

Promise(承诺未来值)

Promise也是一个模版类,通常配合future使用,用于在线程间传递数据同步异步操作的结果

解决的问题

(1) 线程间结果的传递
  • 普通线程函数只能通过参数传递输入数据,但无法直接返回计算结果(除非使用全局变量或指针,但这不够安全)。

  • promise 提供了一种安全、标准化的方式 ,让一个线程(生产者)可以设置一个值,而另一个线程(消费者)可以通过 future 获取这个值。

(2) 异步操作的同步
  • 在异步编程中,我们可能需要等待某个线程完成任务并获取其结果,而 promise/future 提供了一种线程安全的等待机制,避免了手动使用条件变量或锁。
(3) 异常传递
  • 如果一个线程在执行过程中抛出异常,可以通过 promise 将异常传递给 future,让调用方能够捕获并处理它。

实现方案

promise+move

cpp 复制代码
#include <iostream>
#include <future>
#include <thread>

using namespace std;

void task(promise<int> pro) {
	pro.set_value(666);
}


int main() {
	promise<int>ff;
	//绑定future和promise
	future<int>fut = ff.get_future();
	thread t(task,move(ff));
	//获取结果
	cout <<"异步future:"<< fut.get() << endl;
	t.join();

	return 0;
}

这种方案是比较安全的,因为没有使用指针和引用,关键点在于,中间变量作为参数,回调执行完就会释放掉参数pro;

那么问题来了,回调执行完就会释放掉pro,那future还能获取结果吗?

答案是可以的!future从promise读取结果的过程在于set_value写入,执行回调之前future和prommise已经绑定了共享的关系,而set_value就会同步数据给future;即便是后续参数pro和主线程的ff都无效了,future依旧可以获取到正确的结果;

promise+ref

cpp 复制代码
#include <iostream>
#include <future>
#include <thread>

using namespace std;

void task(promise<int>& pro) {
	pro.set_value(666);
}


int main() {
	promise<int>ff;
	//绑定future和promise
	future<int>fut = ff.get_future();
	thread t(task,ref(ff));
	//获取结果
	cout <<"异步future:"<< fut.get() << endl;
	t.join();

	return 0;
}

与上面的区别在于回调的参数是引用,而是实参需要使用ref强调传递的是引用对象,这种方法因涉及引用,所以没有使用move安全一些;

性能分析:

相关推荐
长河几秒前
Java开发者LLM实战——LangChain4j最新版教学知识库实战
java·开发语言
第七序章8 分钟前
【C++STL】list的详细用法和底层实现
c语言·c++·自然语言处理·list
Cyan_RA910 分钟前
SpringMVC @RequestMapping的使用演示和细节 详解
java·开发语言·后端·spring·mvc·ssm·springmvc
逆小舟2 小时前
【Linux】人事档案——用户及组管理
linux·c++
再见晴天*_*3 小时前
SpringBoot 中单独一个类中运行main方法报错:找不到或无法加载主类
java·开发语言·intellij idea
lqjun08275 小时前
Qt程序单独运行报错问题
开发语言·qt
hdsoft_huge6 小时前
Java & Spring Boot常见异常全解析:原因、危害、处理与防范
java·开发语言·spring boot
风中的微尘7 小时前
39.网络流入门
开发语言·网络·c++·算法
未来之窗软件服务7 小时前
幽冥大陆(二)RDIFSDK 接口文档:布草洗涤厂高效运营的技术桥梁C#—东方仙盟
开发语言·c#·rdif·仙盟创梦ide·东方仙盟
混分巨兽龙某某7 小时前
基于Qt Creator的Serial Port串口调试助手项目(代码开源)
c++·qt creator·串口助手·serial port