ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

线程异步通信

2022-04-09 08:31:15  阅读:144  来源: 互联网

标签:std 异步 get 通信 future 线程 include


在线程启动后,我们并不知道什么时候能获取到其返回的结果。在之前的处理中,会用条件变量将共享资源给锁住,让线程完成共享变量的处理后,来通知另外一个线程。

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

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有