线程异步通信
作者:互联网
在线程启动后,我们并不知道什么时候能获取到其返回的结果。在之前的处理中,会用条件变量将共享资源给锁住,让线程完成共享变量的处理后,来通知另外一个线程。
https://zhuanlan.zhihu.com/p/493225557
#include <thread> #include <iostream> #include <future> #include <string> void testFuture(std::promise<std::string> p) { std::this_thread::sleep_for(std::chrono::seconds(2)); std::cout << "begin set value" << std::endl; p.set_value("Test Future value"); //是在set_value就返回值,还是在整个线程函数退出后返回 std::this_thread::sleep_for(std::chrono::seconds(2)); std::cout << "end Test Future" << std::endl; } int main(int argc, char* argv[]) { //异步传输变量 std::promise<std::string> p; //用来获取线程异步值 auto future = p.get_future(); //将p移动到线程函数中,它只允许使用一次,不允许拷贝 auto th = std::thread(testFuture, std::move(p)); std::cout << "begin future get" << std::endl; std::cout << "future get: " << future.get() << std::endl; std::cout << "end future get" << std::endl; th.join(); return 0; }
输出结果:
程序启动后,有两个线程:
主线程打印“begin future get”,然后阻塞等待future.get()返回。
子线程中,先是打印"begin set value",提示要开始调用p.set_value()了,set_value()调用成功后,主线程的
get()方法才返回。也就是说使用promise,future异步获取线程中的结果,不需要等待处理结果的线程返回退出,只要调用了set,就可以立即get到。
packaged_task 异步调用函数打包
- packaged_task 包装函数为一个对象,用于异步调用。其返回值能通过std::future对象访问
- 与bind的区别,可异步调用,函数访问和获取返回值分开调用
packaged_task的使用场景目的很明确,就是适用于函数调用与获取函数返回值分离的场景。比如,一个接口在后台计算某个结果,该结果不会立即返回,我们也不需要等待它返回才能进行下一步操作。就可以使用packaged_task将函数包装一下,并通过get_future接口获得future对象,在我们需要获取结果时,通过future.get()即可。
#include <iostream> #include <string> #include <future> #include <thread> std::string testPack(int index) { std::cout << "begin test pack" << index << std::endl; std::this_thread::sleep_for(std::chrono::seconds(2)); return "testPack return"; } int main() { std::packaged_task<std::string(int)> task(testPack); auto result = task.get_future(); //获取未来值对象,以便在未来获取接口返回值 std::thread th(std::move(task), 110); //在子线程中调用接口 //测试是否超时 //在实际的业务代码中也要有超时判断,防止接口内部死锁,一直阻塞等待结果 for (int i = 0; i < 30; i++) { if (result.wait_for(std::chrono::milliseconds(100)) != std::future_status::timeout) continue; } std::cout << "begin get result" << std::endl; std::cout << "result get " << result.get() << std::endl; //阻塞等待返回结果 th.join(); getchar(); return 0; }
std::async
C++异步运行一个函数,并返回保有其结果的std::future
- launch::deferred 延迟执行,并且不创建线程,在调用wait和get时,调用函数代码
- launch::async 创建线程(默认)
- 返回的线程函数的返回值类型std::future<xxx> (xxx表示线程函数的返回值类型)
- re.get()阻塞等待获取结果
async与packaged_task的作用相似,都是包装一个函数调用,在未来获取该调用的返回值。不同的是async可以在内部选择创建线程,将thread封装了起来。
代码示例:
1. 不创建线程启动异步任务
string testAsync(int index) { cout << index<< " begin in testAsync, id:" << this_thread::get_id() << endl; this_thread::sleep_for(chrono::seconds(3)); return "testAsync string return"; } int main() { //创建异步线程 //不创建线程启动异步任务 cout << "main thread ID" << this_thread::get_id() << endl; auto future = async(launch::deferred, testAsync, 100); this_thread::sleep_for(chrono::seconds(1)); cout << "begin future get" << endl; cout << "get:"<< future.get() <<endl; cout << "end future get" << endl; getchar(); return 0; }
启动后:
//先打印 main thread ID788
//间隔一秒
begin future get
//间隔三秒
100 begin in testAsync, id:788
get:testAsync string return
end future get
说明async在不创建线程的情况下是和主线程同步的。并且只有在调用future.get()方法时,才会进入到被包装函数中执行。
2. 创建线程启动异步任务
string testAsync(int index) { cout << index<< " begin in testAsync, id:" << this_thread::get_id() << endl; this_thread::sleep_for(chrono::seconds(3)); return "testAsync string return"; } int main() { //创建线程启动异步任务 cout << "=====创建异步线程====" << endl; auto future2 = async(testAsync, 101); this_thread::sleep_for(chrono::seconds(1)); cout << "begin future2 get" << endl; cout << "get:" << future2.get() << endl; cout << "end future2 get" << endl; getchar(); return 0; }
打印结果
//执行后先打印以下两行
=====创建异步线程==== 101 begin in testAsync, id:11176
//间隔一秒 begin future2 get
//间隔两秒 get:testAsync string return end future2 get
以创建线程的方式执行异步任务,一旦将函数包装后,就会立即执行,并且在get()时阻塞等待结果。
标签:std,异步,get,通信,future,线程,include 来源: https://www.cnblogs.com/y4247464/p/16115185.html