C++多线程学习(四)异步编程

前面刚大写特写多线程同步,这里怎么又扯到异步编程了,嘿嘿,其时两者的'步'不是一个东西,前面讲的同步,是对于所访问资源的有序处理,此处就是在接口层面,是被调用方是否执行完毕才停止阻塞,需要等待执行完毕就是同步,否则就是异步。熟悉windows编程的同学很容易就联想到一个东西了,SendMessage、PostMessage,其机制,优势、缺陷网上有太多的资料了,有过相关编程经验的人也都清楚其是怎么回事了。那么,这里我们深入探讨下,他们到底是如何实现的呢?

同步这个不多说,顺序执行命令就是同步了,不需要额外处理什么,那么异步是如何实现的呢?首先我们看下异步的特点。

  • 接口被调用不阻塞,调用线程可以继续往下执行
  • 调用线程有方法可以获取到接口执行完毕的通知,并获取其返回值

 首先看接口不阻塞,代码内存肯定共用,这个不做他想,肯定是创建一个线程,来执行这个接口函数。再看下接口执行完毕通知调用线程,这个我们前面学的条件变量可以解决,这样一看异步接口也不是很复杂吗,看示例

//future1.cpp 使用全局变量传递被调用线程返回结果,使用条件变量通知调用线程已获得结果

#include <vector>
#include <numeric>
#include <iostream>
#include <chrono>
#include <thread>
#include <mutex>
#include <condition_variable>

int res = 0;						//保存结果的全局变量
std::mutex mu;						//互斥锁全局变量
std::condition_variable cond;       //全局条件变量
 
void accumulate(std::vector<int>::iterator first,
                std::vector<int>::iterator last)
{
    int sum = std::accumulate(first, last, 0);      //标准库求和函数
    std::unique_lock<std::mutex> locker(mu);
    res = sum;
    locker.unlock();
    cond.notify_one();              // 向一个等待线程发出“条件已满足”的通知
}
 
int main()
{
    std::vector<int> numbers = { 1, 2, 3, 4, 5, 6 };
    std::thread work_thread(accumulate, numbers.begin(), numbers.end());

    std::unique_lock<std::mutex> locker(mu);
    cond.wait(locker, [](){ return res;});   //如果条件变量被唤醒,检查结果是否被改变,为真则直接返回,为假则继续等待
    std::cout << "result=" << res << '\n';
    locker.unlock();
    work_thread.join();         //阻塞等待线程执行完成
 
    getchar();
    return 0;
}

引入了三个全局变量res、mu、cond,接口还被入侵,调用线程获取结果还要增加unique_lock,对于工程设计的破坏巨大。那么有没有优雅一点的接口可以实现相关功能呢?当然有,直接给出终极方案std::async接口。直接看例子

//future4.cpp 使用async传递被调用线程返回结果

#include <vector>
#include <thread>
#include <future>
#include <numeric>
#include <iostream>
#include <chrono>
 
int accumulate(std::vector<int>::iterator first,
                std::vector<int>::iterator last)
{
    int sum = std::accumulate(first, last, 0);
    return sum;
}
 
int main()
{
    // 演示用 async 在线程间传递结果。
    std::vector<int> numbers = { 1, 2, 3, 4, 5, 6 };
    auto accumulate_future = std::async(std::launch::async, accumulate, numbers.begin(), numbers.end());		//auto可以自动推断变量的类型
    std::cout << "result=" << accumulate_future.get() << '\n';
 
    getchar();
    return 0;
}

std::async接口替我们完成了创建线程的过程,接口返回的std::future变量替换了前面三个全局变量的限制,std::future的get接口替我们完成了额外增加条件向量的尴尬。果然,优雅的尽头就是封装,不过了解封装之前的代码有助于我们更好的理解接口。

  • 3
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值