1、普通异步函数
如前面的博客介绍的,这个库中提供了async::spawn方法,这个方法通常用来启动异步函数,这个框架会利用线程池去完成函数,因此要注意数据安全。正因为将任务放到了单独的线程执行,并且还有调度开销,因此简单的任务最好不要使用这种方法,得不偿失。示例代码如下:
void demo_async1() {
std::mutex mutex;
auto task1 = async::spawn(
[&mutex]{
{
std::lock_guard<std::mutex> lock(mutex);
std::cout << "this is in async thread" << std::endl;
}
return "hello world!!!";
});
while(!task1.ready()) {
std::lock_guard<std::mutex> lock(mutex);
std::cout << "this is in main thread" << std::endl;
}
task1.wait();
// 这里会获取任务的返回值,即"hello world!!!"
auto ret = task1.get();
std::cout << ret << std::endl;
};
2、带有子任务的普通异步函数
async::spawn函数返回的仍然是一个任务,因此可以连续使用then来执行子任务,示例代码如下:
void demo_async2() {
async::spawn([] {
return "hello world";
}).then([](const std::string& s) {
return s;
}).then([](async::task<std::string> task) {
std::cout << task.get() << std::endl;
});
}
有没有发现第一个子任务所执行的函数参数是std::string,而第二个子任务所执行的函数参数是async::taskstd::string task,而前面两个任务返回的都是字符串。这是因为异步编程中的 .then() 方法和 async::task 类型的处理方式有些特殊。在链式调用中,.then() 并不仅仅是一个普通的函数调用,它是用来接收一个异步任务完成后的结果,并且会返回一个新的异步任务。这意味着第一个子任务返回的并不是字符串,返回的字符串会被封装成async::taskstd::string,所以第二个子函数的参数类型必须是 async::taskstd::string。而主任务的返回值是std::string,所以第一个子任务的函数参数可以是std::string。
3、when_any和when_all的使用
when_any是任务集合中有一个任务完成就会返回,when_all是多有的任务完成才会返回。需要注意的是,when_any并不是第一个任务完成了就不执行其他的任务,其它的任务仍在执行,只不过when_any不会等他们执行完再返回。这里在测试的时候,如果测试when_all,一定要先注释when_any,否则程序会崩溃,原因就是task和shared_task的原因。它们返回的包含结果的数据结构都是std::tuple类型的,想取得结果要么使用辅助函数,要么使用std::get<0>(results).get()这种。不能使用for遍历,因为tuple的各元素大小可能不一样。也不可以使用std::get<first_result.index>,原因很简单,模版函数需要再编译时确定值,而不可以在运行时确定。
void demo_async3() {
// 定义三个异步任务,分别模拟不同的执行时间
auto task1 = async::spawn([] {
std::this_thread::sleep_for(std::chrono::seconds(3)); // 模拟耗时任务
std::cout << "Task 1 completed!" << std::endl;
return 1;
});
auto task2 = async::spawn([] {
std::this_thread::sleep_for(std::chrono::seconds(2)); // 模拟耗时任务
std::cout << "Task 2 completed!" << std::endl;
return 2;
});
auto task3 = async::spawn([] {
std::this_thread::sleep_for(std::chrono::seconds(1)); // 模拟耗时任务
std::cout << "Task 3 completed!" << std::endl;
return 3;
});
// // 使用 when_any 等待最早完成的任务
// auto any_result = async::when_any(task1, task2, task3);
// any_result.wait(); // 等待第一个任务完成
// auto first_result = any_result.get();
// std::cout << "First completed task returned: " << first_result.index << std::endl;
// 使用 when_all 等待所有任务完成
auto all_result = async::when_all(task1, task2, task3);
all_result.wait(); // 等待所有任务完成
auto results = all_result.get();
// 因为是Tuple,静态容器,每个元素的大小可能不一样,所以可以用这种方式访问
// 如果是C++1,可以使用std::apply()来遍历tuple
std::cout << std::get<0>(results).get() << std::endl;
std::cout << std::get<1>(results).get() << std::endl;
std::cout << std::get<2>(results).get() << std::endl;
}
4、async::cancellation_token的使用
该异步框架提供了一个async::cancellation_token,它主要用来控制子任务的执行进度,是不是在主线程中取消子任务的执行,这样可以使得子线程中通过其控制子线程内部的执行进度,是不是取消(当然也可以做一些逻辑的控制)
void demo_async4() {
async::cancellation_token c;
auto t = async::spawn([&c] {
std::cout << "-----line 68" << std::endl;
async::interruption_point(c);
while(!c.is_canceled());
std::cout << "-----line 70" << std::endl;
});
sleep(1);
std::cout << "-----line 79" << std::endl;
c.cancel();
t.get();
std::cout << "-----line 82" << std::endl;
}
5、事件任务的使用
我认为时间任务的主要作用是在主线程中控制子任务的执行时间点,并可以像子任务重设置参数。
void demo_async5() {
async::event_task<int> e;
auto t = e.get_task();
// 这里只是将后面的任务放到了e的continuation_vector
t.then([](int result) { std::cout << result << std::endl; });
// 执行主任务,并将参数传给子任务,触发子任务
e.set(42);
}
6、共享任务的使用
共享任务的优点是可以多次获取任务的结果,不像普通的任务那样,获取完结果,就会把内存释放掉。缺点是使用了引用计数,增加了资源消耗,但是现代计算机中,这些资源的消耗造成的影响较小,这里的代码必须加share(),根因和task类shared_task类的定义有关系,task类不允许拷贝,但是允许移动构造,但是shared_task都是可以的,模仿的std::future和std::shared_future的关系。
// 从测试代码中可以看出,我们可以利用共享任务,将其以参数的形式传到其它任务中
void demo_async6() {
// 使用 async::spawn 创建异步任务并使用 .share() 方法共享
auto t = async::spawn([] {
std::cout << "Parent task" << std::endl;
return 42; // 返回一些结果
}).share();
// 创建两个任务,它们共享 t
auto task1 = async::spawn([t] {
auto result = t.get(); // 获取共享任务的结果
std::cout << "Task 1 result: " << result << std::endl;
});
auto task2 = async::spawn([t] {
auto result = t.get(); // 获取共享任务的结果
std::cout << "Task 2 result: " << result << std::endl;
});
// 等待任务完成
task1.get();
task2.get();
7、测试程序
直接贴代码
#include <iostream>
#include <mutex>
#include <ctime>
#include <unistd.h>
#include "../include/async++.h"
/*
上面的示例
*/
int main() {
// demo_async1();
// demo_async2();
demo_async3();
// demo_async4();
//
标签:std,task,cout,示例,demo,c++,asyn,任务,async
From: https://blog.csdn.net/xiaoan08133192/article/details/145311448