📢博客主页:https://blog.csdn.net/2301_779549673
📢博客仓库:https://gitee.com/JohnKingW/linux_test/tree/master/lesson
📢欢迎点赞 👍 收藏 ⭐留言 📝 如有错误敬请指正!
📢本文由 JohnKi 原创,首发于 CSDN🙉
📢未来很长,值得我们全力奔赴更美好的生活✨
文章目录
📢前言
紧接上回,接下来笔者将介绍rpc框架的最重要的三个第三方库,方便大家理解
这回是 fature 篇
🏳️🌈1 std::future
1.1 介绍
std::future是C++11标准库中的一个模板类,它表示一个异步操作的结果。当我们在多线程编程中使用异步任务时,std::future可以帮助我们在需要的时候获取任务的执行结果。
std::future的一个重要特性是能够阻塞当前线程,直到异步操作完成,从而确保我们在获取结果时不会遇到未完成的操作。
1.2 应用场景
异步任务:当我们需要在后台执行一些耗时操作时,如网络请求或计算密集型任务等,std:future可以用来表示这些异步任务的结果。通过将任务与主线程分离,我们可以实现任务的并行处理,从而提高程序的执行效率
并发控制:在多线程编程中,我们可能需要等待某些任务完成后才能继续执行其他操作。通过使用std::future,我们可以实现线程之间的同步,确保任务完成后再获取结果并继续执行后续操作
结果获取:std::future提供了一种安全的方式来获取异步任务的结果。我们可以使用std::future:get()函数来获取任务的结果,此函数会阻塞当前线程,直到异步操作完成。这样,在调用get()函数时,我们可以确保已经获取到了所需的结果
🏳️🌈 2 用法示例
2.1 使用 std::async关联异步任务
std::async是一种将任务与std::future关联的简单方法。它创建并运行一个异步任务,并返回一个与该任务结果关联的std::future对象。默认情况下,std:async是否启动一个新线程,或者在等待future时,任务是否同步运行都取决于你给的 参数。这个参数为std::launch类型:
std:.launch::deferred 表明该函数会被延迟调用,直到在future上调用get()或者wait()才会开始。执行任务
std::launch::async表明函数会在自己创建的线程上运行。
std::launch::deferred std::launch:async内部通过系统等条件自动选择策略。
#include <iostream>
#include <future>
#include <thread> // [!] 必须包含此头文件
#include <chrono> // [!] 必须包含此头文件
int Add(int num1, int num2){
return num1 + num2;
}
int main(){
// async(launch __policy, _Fn&& __fn, _Args&&... __args)
// __policy:指定策略,可以是launch::async或launch::deferred,默认为launch::async
// launch::async:异步执行,内部创建一个线程执行函数,函数运行结果通过future获取
// launch::deferred:延迟执行,获取结果的时候再去执行任务
// _Fn&& __fn:要执行的函数
// _Args&&... __args:函数的参数
std::future<int> res = std::async(std::launch::async, Add, 11, 22);
std::this_thread::sleep_for(std::chrono::seconds(1));
std::cout << "-------------------------------\n";
// get():获取异步执行的结果
std::cout << res.get() << std::endl;
return 0;
}
编译结果
代码流程图
主线程:
1. 创建延迟任务 res = async(deferred, Add) → 任务未启动
2. 休眠 1 秒 → 主线程空闲
3. 调用 res.get() → 触发任务执行
- 执行 Add(11, 22) → 返回 33
4. 输出结果 → 结束
任务线程(无):
- 由于使用 deferred 策略,无独立线程创建。
2.2 异步执行std::packaged_task任务
#include <iostream>
#include <future>
#include <thread>
int Add(int num1, int num2){
return num1 + num2;
}
int main(){
// 1. 封装任务
// std::packaged_task<int(int, int)> task(Add);
auto task = std::make_shared<std::packaged_task<int(int, int)>>(Add);
// 2. 获取任务包关联的future对象
std::future<int> res = task->get_future();
// 3. 执行任务
std::thread thr([task](){ (*task)(11, 22); });
// 4. 获取结果
std::cout << res.get() << std::endl;
return 0;
}
编译结果
代码运行图
主线程:
1. 创建 packaged_task(封装 Add)
2. 获取 future 对象
3. 启动子线程执行任务
4. 阻塞等待结果 → 输出 33
子线程:
1. 执行 (*task)(11, 22)
2. 计算结果 33 → 通过 future 传递结果
2.3 使用std::promise和std::future配合
std::promise提供了⼀种设置值的⽅式,它可以在设置之后通过相关联的std::future对象进⾏读取。换种
说法就是之前说过std::future可以读取⼀个异步函数的返回值了, 但是要等待就绪, ⽽std::promise就提供⼀种 ⽅式⼿动让 std::future就绪
#include <iostream>
#include <future>
#include <thread>
#include <memory>
int Add(int num1, int num2){
return num1 + num2;
}
int main(){
// 1. 在使用的时候,就是先实例化一个指定结果的 promise 对象
std::promise<int> pro;
// 2. 通过promise对象,获取关联的 future 对象
std::future<int> res = pro.get_future();
// 3. 在任意位置给promise设置数据,就可以通过关联的 future 获取到这个设置的数据了
std::thread thr([&pro](){
int sum = Add(11, 22);
pro.set_value(sum);
});
std::cout << res.get() << std::endl;
thr.join();
return 0;
}
编译结果
代码运行图
主线程:
1. 创建 promise 和 future → pro 和 res
2. 启动子线程 thr → 执行 Add(11, 22)
3. 调用 res.get() → 阻塞等待结果
4. 子线程设置值 → res.get() 返回 33
5. 输出结果 → 结束
子线程:
1. 计算 11 + 22 → sum = 33
2. 调用 pro.set_value(33) → 唤醒主线程
👥总结
本篇博文对 【从零实现Json-Rpc框架】- 第三方库介绍 - fature篇 做了一个较为详细的介绍,不知道对你有没有帮助呢
觉得博主写得还不错的三连支持下吧!会继续努力的~