【C++11】深度解析--异步操作(什么是异步?异步有那些操作?异步操作有什么用呢?)

news2024/11/16 20:56:04

目录

一、前言

二、什么是异步操作呢?

🔥异步的概念🔥

🔥异步的生活案例说明🔥

三、异步有那些操作呢? 

🔥std::future🔥

💢std::future 的概念💢

💢主要成员函数💢

💧std::future 与 std::async 💧

💧std::future 与 std::packaged_task💧 

💧std::future与std::promise💧  

四、总结 

五、共勉


一、前言

        如何让程序更高效、更快速一直是开发者追求的目标C++11】 引入的异步操作,为我们提供了一个解决这个问题的新方式。通过使用 std::async std::future 等工具,我们可以轻松地处理并发任务,让程序在处理复杂操作时不再卡顿。
        本篇文章将带你轻松入门 【C++11】 的异步操作,从基础概念到实际应用,逐步讲解如何利用这些新工具编写更高效的程序。

 二、什么是异步操作呢?

🔥异步的概念🔥

异步操作同步操作 相对在同步操作中,程序必须按顺序执行各个任务,等待前一个任务完成后才能继续执行下一个任务。在异步操作中,程序可以启动一个耗时任务,然后继续执行其他任务,而无需等待该耗时任务完成。当耗时任务完成后,程序会得到通知并处理结果。 

🔥异步的生活案例说明🔥

点餐和上菜

想象你在餐厅点餐的过程,这是一个很好理解异步概念的例子。

 同步操作的情况:

  • 你走进餐厅,点了一份牛排。
  • 你站在柜台前等着,直到牛排做好并送到你手上,你才能去找座位开始吃饭。

在这个例子中:
顾客(主线程)发起一个任务(子线程做牛排),做牛排的过程中顾客没去做别的事情而是死等,这就是一条时间线(同步),此时效率相对较低

异步操作的情况: 

  • 你走进餐厅,点了一份牛排。
  • 你点完餐后,服务员给你一个号牌,你可以去找座位坐下。
  • 在等待牛排做好期间,你可以先喝点水,聊聊天,或者刷刷手机。
  • 当牛排做好后,服务员会叫号或者送到你桌前,你再开始吃饭。

在这个例子中:
顾客(主线程)发起一个任务(子线程做牛排),做牛排的过程中顾客去做的别的事情,有两条时间线(异步),此时效率相对较高


三、异步有那些操作呢? 

        由于 多线程程序中的任务大都是异步 的,主线程 和 子线程 分别执行不同的任务,如果想要在主线中得到某个子线程任务函数返回的结果可以使用【C++11】提供的 std::future类,这个类需要和其他类或函数搭配使用

🔥std::future🔥

💢std::future 的概念💢

std::future 是C++11标准库中的⼀个模板类它表⽰⼀个异步操作的结果(完成线程间的通信)。当我们在多线程编程中使⽤ 异步任务时,std::future 可以帮助我们在需要的时候获取任务的执⾏结果。std::future 的⼀个重要特性 是能够阻塞当前线程,直到异步操作完成,从⽽确保我们在获取结果时不会遇到未完成的操作。
它主要与 std::asyncstd::promisestd::packaged_task 一起使用。

所需的头文件:

#include <future>

💢主要成员函数💢

get() 

get() std::future 最重要的成员函数。它用于获取异步操作的结果。如果结果还不可用,get() 会阻塞调用线程,直到结果可用。 

T get();
  • 如果异步操作成功完成,get() 返回结果。
  • 如果异步操作抛出异常,get() 重新抛出该异常。

valid() 

valid() 用于检查 std::future 是否有一个与之关联的共享状态。如果 std::future 还没有获取过结果或者还没有被移动,它返回 true。 

bool valid() const noexcept;

wait() 

wait() 用于阻塞调用线程,直到异步操作完成。 

void wait() const;

wait_for() 

wait_for() 用于阻塞调用线程,直到异步操作完成或者指定的时间段过去。 

template< class Rep, class Period >
std::future_status wait_for( const std::chrono::duration<Rep, Period>& rel_time ) const;

返回值:

  • std::future_status::ready异步操作已完成。
  • std::future_status::timeout超时时间已到,但异步操作尚未完成。
  • std::future_status::deferred异步操作被延迟(即 std::launch::deferred)。


下面我们将会 结合std::asyncstd::promisestd::packaged_task 举例说明 std::future 的成员函数的各种用法 


💧std::future 与 std::async 💧

std::async 是 【C++11】 引入的一个函数模板,用于启动异步任务。它允许你将某个函数的调用放到一个独立的线程中执行,并返回一个 std::future 对象来获取函数的结果。

语法 

#include <future>

template< class Function, class... Args >
std::future<typename std::result_of<Function(Args...)>::type>
async( std::launch policy, Function&& f, Args&&... args );

template< class Function, class... Args >
std::future<typename std::result_of<Function(Args...)>::type>
async( Function&& f, Args&&... args );
  • policy启动策略,可以是 std::launch::asyncstd::launch::deferred,或者是它们的组合。
    • std::launch::async在新线程中异步执行任务。
    • std::launch::deferred延迟执行任务,直到调用 futuregetwait 成员函数。
  • f要执行的函数。
  • args传递给函数 f 的参数。

返回值 

返回一个 std::future 对象,用于获取异步任务的结果。 


异步任务的启动策略 

  • std::launch::async:强制在新线程中异步执行任务。
  • std::launch::deferred:延迟执行任务,直到调用 std::futuregetwait 成员函数。
  • 默认行为:如果未指定 policy,则系统将自动选择合适的策略。

举例说明: 模拟一个去餐厅点牛排的过程     进行异步操作 

#include <iostream>
#include <thread>
#include <future>
#include <chrono>

// 模拟一个耗时操作的函数
int cook_steak(int timesteak) 
{
    std::cout << "make steak" << std::endl;
    std::this_thread::sleep_for(std::chrono::seconds(timesteak)); // 模拟做牛排的时间
    return 1; // 假设 1 代表牛排已做好
}

int main() 
{
    // 创建一个 packaged_task 对象,封装耗时操作
    std::packaged_task<int(int)> task(cook_steak);

    // 获取与 packaged_task 相关联的 future 对象
    std::future<int> result = task.get_future();

    // 启动任务,任务将在当前线程执行
    std::thread task_thread(std::move(task), 5);

    // 在等待牛排的同时,可以做其他事情   每过一秒检查一次
    while (result.wait_for(std::chrono::seconds(1)) != std::future_status::ready) 
    {
        std::cout << "...Doing other things while waiting for the steak...\n";
    }

    // 等待任务完成并获取结果
    int steak_status = result.get();
    if (steak_status == 1) 
    {
        std::cout << "Steak is ready! Time to eat.\n";
    }

    // 确保任务线程完成
    task_thread.join();

    return 0;
}

输出结果:

make steak
...Doing other things while waiting for the steak...
...Doing other things while waiting for the steak...
...Doing other things while waiting for the steak...
...Doing other things while waiting for the steak...
...Doing other things while waiting for the steak...
Steak is ready! Time to eat.

此时我们发现,子线程 和 主线程 同时执行 在子线程运行的时候,主线程可以做其它的事情,而不受子线程的影响。 这就是  ---- 异步操作


如果将 async 模式  改为  deferred 模式 

deferred 模式  它表示任务将被推迟到调用 get()wait() 时才执行。简单来说,deferred 模式不会在任务启动时立即执行任务,而是将任务的执行推迟到需要结果时。 

#include <iostream>
#include <thread>
#include <future>
#include <chrono>

// 模拟一个耗时操作的函数
int cook_steak(int timesteak) 
{
    std::cout << "make steak" << std::endl;
    std::this_thread::sleep_for(std::chrono::seconds(timesteak)); // 模拟做牛排的时间
    return 1; // 假设 1 代表牛排已做好
}

int main() 
{
    // 启动异步任务做牛排
    std::future<int> result = std::async(std::launch::deferred, cook_steak , 5);

    
    std::cout << "...Doing other things while waiting for the steak...\n";


    // 获取异步任务的结果(即牛排是否做好)
    // std::future<int>::get() 用于获取异步任务的结果,如果没有结果就会阻塞
    int steak_status = result.get();
    if (steak_status == 1) 
    {
        std::cout << "Steak is ready! Time to eat.\n";
    }

    return 0;
}

 输出结果:

...Doing other things while waiting for the steak...
make steak
Steak is ready! Time to eat.

我们发现,deferred 模式不会在任务启动时立即执行任务,而是将任务的执行推迟到需要结果时。 


💧std::future 与 std::packaged_task💧 

std::packaged_task 是 C++11 提供的一个工具,用于将任何可调用对象(如函数、函数对象、lambda 表达式等)封装成一个任务,然后可以通过 std::future 来获取任务的结果。它可以用于异步操作和线程操作,将任务与结果进行关联。 

 std::packaged_task 的基本使用

  • 定义任务:封装一个任务,例如一个函数或 lambda 表达式。
  • 创建 std::packaged_task 对象:将任务封装到 std::packaged_task 对象中。
  • 获取 std::future 对象:通过 std::packaged_task::get_future() 方法获取 std::future 对象,用于获取任务的结果。
  • 启动任务:通过 std::thread 或直接调用 operator() 启动任务。
  • 获取结果:通过 std::future::get() 方法获取任务的结果。

举例说明: 模拟一个去餐厅点牛排的过程     进行异步操作  

#include <iostream>
#include <thread>
#include <future>
#include <chrono>

// 模拟一个耗时操作的函数
int cook_steak(int timesteak) 
{
    std::cout << "make steak" << std::endl;
    std::this_thread::sleep_for(std::chrono::seconds(timesteak)); // 模拟做牛排的时间
    return 1; // 假设 1 代表牛排已做好
}

int main() 
{
    // 创建一个 packaged_task 对象,封装耗时操作
    std::packaged_task<int(int)> task(cook_steak);

    // 获取与 packaged_task 相关联的 future 对象
    std::future<int> result = task.get_future();

    // 启动任务,任务将在当前线程执行
    std::thread task_thread(std::move(task), 5);

    // 主线程可以继续执行其他操作
    std::cout << "...Doing other things while waiting for the steak...\n";

    // 等待任务完成并获取结果
    int steak_status = result.get();
    if (steak_status == 1) 
    {
        std::cout << "Steak is ready! Time to eat.\n";
    }

    // 确保任务线程完成
    task_thread.join();

    return 0;
}

 输出结果:

make steak
...Doing other things while waiting for the steak...
...Doing other things while waiting for the steak...
...Doing other things while waiting for the steak...
...Doing other things while waiting for the steak...
...Doing other things while waiting for the steak...
Steak is ready! Time to eat.

总结:

  • 异步操作:由于 std::thread 用于在新线程中执行任务,因此代码中确实存在异步操作。主线程和子线程并行执行任务和其他操作。
  • 子线程生成std::thread 的使用确保了新线程的创建,这意味着 cook_steak(5) 会在子线程中执行,而主线程则继续执行其他操作。

关键点:异步操作是通过 std::thread 来实现的,确保了任务在子线程中并发执行,而主线程可以在此期间进行其他操作。


💧std::future与std::promise💧  

std::promise 是 C++ 标准库中用于与 std::future 配合的一个类,用于在异步操作中设置共享状态。它允许你在一个线程中设置结果,并在另一个线程中读取这个结果。

std::promise 的作用

  • std::promise 提供了一个接口,用于设置一个异步操作的结果。它与 std::future 一起使用,std::future 用于获取这个结果。
  • 典型用法:你通常在一个线程中创建一个 std::promise 对象,并将它的 std::future 传递给另一个线程。第一个线程会设置结果,而第二个线程则会获取这个结果。
#include <iostream>
#include <thread>
#include <future>
#include <chrono>

// 模拟一个耗时操作的函数
void cook_steak(std::promise<int> prom, int timesteak) 
{
    std::cout << "make steak" << std::endl;
    std::this_thread::sleep_for(std::chrono::seconds(timesteak)); // 模拟做牛排的时间
    prom.set_value(1); // 设置 promise 的结果
}

int main() 
{
    // 创建一个 promise 对象
    std::promise<int> prom;

    // 获取与 promise 相关联的 future 对象
    std::future<int> result = prom.get_future();

    // 启动线程来执行任务
    std::thread task_thread(cook_steak, std::move(prom), 5);

    // 在等待牛排的同时,可以做其他事情   每过一秒检查一次
    while (result.wait_for(std::chrono::seconds(1)) != std::future_status::ready) 
    {
        std::cout << "...Doing other things while waiting for the steak...\n";
    }

    // 获取异步任务的结果(即牛排是否做好)
    int steak_status = result.get(); // 这里会阻塞直到任务设置值
    if (steak_status == 1) 
    {
        std::cout << "Steak is ready! Time to eat.\n";
    }

    // 确保任务线程完成
    task_thread.join();

    return 0;
}

 输出结果:

make steak
...Doing other things while waiting for the steak...
...Doing other things while waiting for the steak...
...Doing other things while waiting for the steak...
...Doing other things while waiting for the steak...
...Doing other things while waiting for the steak...
Steak is ready! Time to eat.

总结

  • std::promise 允许你在一个线程中设置结果,另一个线程中获取这个结果。
  • std::future 用于获取 std::promise 设置的值,并可以在需要时阻塞当前线程直到结果可用。
  • 使用 std::promisestd::future 的主要好处是它们提供了清晰的异步任务通信机制,使得任务结果的传递变得简单和安全。

四、总结 

1️⃣: 使用async()函数,是多线程操作中最简单的一种方式,不需要自己创建线程对象,并且可以得到子线程函数的返回值。

2️⃣:使用std::promise类,在子线程中可以传出返回值也可以传出其他数据,并且可选择在什么时机将数据从子线程中传递出来,使用起来更灵活。

3️⃣:使用std::packaged_task类,可以将子线程的任务函数进行包装,并且可以得到子线程的返回值。

五、共勉

以下就是我对 【C++11】异步操作 的理解,如果有不懂和发现问题的小伙伴,请在评论区说出来哦,同时我还会继续更新对 【C++11】 的理解,请持续关注我哦!!!      

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1966938.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

SmolLM-HuggingFace发布的高性能小型语言模型

SmolLM是什么&#xff1f; SmolLM是由 Huggingface 最新发布的一系列最先进的小型语言模型&#xff0c;有三种规格&#xff1a;1.35亿、3.6亿和17亿个参数。这些模型建立在 Cosmo-Corpus 上&#xff0c;Cosmo-Corpus 是一个精心策划的高质量训练数据集。Cosmo-Corpus 包括 Cos…

AT24C08系列eeprom总结

内存大小说明&#xff1a;单位&#xff08;bits(位&#xff09; AT24C02A&#xff0c;2K bits串行EEPROM&#xff1a;内部组织为256页&#xff0c;每页1字节&#xff0c; AT24C04A&#xff0c;4K bits串行EEPROM&#xff1a;4K内部组织为256页&#xff0c;每页2字节。 AT24C…

拯救丢失数据,这三款数据恢复软件你不可错过

数据丢失真的很烦人&#xff0c;无论是手滑删除了重要文件&#xff0c;还是电脑突然崩溃&#xff0c;那些珍贵的照片、文档、视频&#xff0c;一瞬间就仿佛人间蒸发了一样。但别担心&#xff0c;科技的力量总能给我们带来希望&#xff0c;数据恢复软件就是我们的救星。我用过了…

如何选择开放式耳机?2024五款热门机型推荐!

耳机在我们日常通勤和运动锻炼中扮演着重要的角色&#xff0c;它不仅帮助我们放松和振奋&#xff0c;还提供了随时可得的安慰和动力。选择一款合适的耳机非常关键&#xff0c;开放式耳机因其不挤压耳道的设计&#xff0c;在多种使用场景下都能提供良好的适应性&#xff0c;特别…

本地node搭建web服务器

首先确认自己的电脑已经安装了node.js 1.创建一个node服务文件 创建一个node-serve文件夹&#xff0c;然后在当前文件下输入初始化node项目命令。 npm init然后一直按回车即可&#xff0c;完成之后生成一个 package.json 文件。 2.在当前文件夹下新建一个 index.js 的文件&…

IT人求职就业手册:如何在数字时代脱颖而出

&#x1f482; 个人网站:【 摸鱼游戏】【网址导航】【神级代码资源网站】&#x1f91f; 一站式轻松构建小程序、Web网站、移动应用&#xff1a;&#x1f449;注册地址&#x1f91f; 基于Web端打造的&#xff1a;&#x1f449;轻量化工具创作平台&#x1f485; 想寻找共同学习交…

《数据库技术及其对我国企业发展的重大贡献》

数据库技术及其对我国企业发展的重大贡献 一、夯实数字化基础&#xff0c;助力企业转型二、提升数据处理能力&#xff0c;增强企业核心竞争力三、保障数据安全&#xff0c;筑牢企业发展防线四、推动技术创新&#xff0c;引领企业未来发展五、构建数据生态&#xff0c;激发企业创…

Vue + View-ui-plus Upload实现手动上传

本文实现Vue Upload组件多文件手动上传&#xff0c;支持上传图片&#xff08;image&#xff09;、压缩文件(zip/rar)、表格(excel)、pdf 一、dom结构 <Row><Col :span"19"></Col><Col :span"2"><div class"ivu-btn-uplo…

基于自监督学习的多维MRI数据去噪

摘要 目的&#xff1a;开发一种基于自监督学习方法的高维MRI数据去噪框架&#xff0c;该框架无需基准真值。 方法&#xff1a;定量MRI面临着信噪比(SNR)的限制&#xff0c;而且复杂的非线性信号模型使得拟合过程容易受到噪声的影响。为了解决这些问题&#xff0c;本研究提出了…

智慧停车场反向寻车功能:蓝牙iBeacon技术赋能地下车库精准定位与导航

随着城市车辆数量的激增&#xff0c;传统停车场面临着管理效率低下、停车难、寻车难等问题。智慧停车场导航停车和反向寻车技术的引入&#xff0c;为解决这些问题提供了创新方案&#xff0c;极大提升了停车场的智能化水平和用户体验。 智慧停车场导航系统的技术架构 1.基于3D…

ETL数据集成丨快速将MySQL数据迁移至Doris数据库

随着大数据技术的迅速发展&#xff0c;越来越多的企业开始寻求高效、灵活的数据存储与分析解决方案。Apache Doris&#xff08;原名 Palo&#xff09;作为一款高性能的MPP&#xff08;大规模并行处理&#xff09;分析型数据库&#xff0c;凭借其在OLAP场景下的卓越表现&#xf…

丝滑的动态Dock栏设计:交互式网页元素的实现

动态Dock栏设计&#xff1a;交互式网页元素的实现 在现代网页设计中&#xff0c;交互性是一个关键要素&#xff0c;它能够提升用户体验并使网页更加生动。本文将深入分析一个交互式Dock栏的设计案例&#xff0c;它通过CSS自定义属性和JavaScript事件处理&#xff0c;实现了一个…

redis的集群(高可用)

redis集群的三种模式&#xff1a; 主从复制 奇数 三台 一主两从 哨兵模式 3 一主两从 cluster集群 六台 主从复制&#xff1a;和mysql的主从复制类似&#xff0c;主可以写&#xff0c;写入主的数据通过RDB方式把数据同步到从服务器&#xff0c;从不能更新到主&#xff0c;也…

UML类图 详解

总目录 前言 作为一个程序员&#xff0c;我们经常会使用UML来绘制各种图&#xff08;UML中定义了用例图、类图、时序图、协作图等九种&#xff09;&#xff0c;类图就是其中常用图之一。设计模式中经常会用到的是类图&#xff0c;本文主要是学习UML类图相关资料后的汇总笔记&a…

【原创】分析JDK17加载Sybase驱动出现递归调用的原因并解决其加载问题

前言 最近好久没发文章了&#xff0c;原因是AI太强了&#xff0c;随便问一句答案就有了&#xff0c;节约了很多折腾的时间&#xff0c;也就没法作为原创文章发布了&#xff0c;还有就是很多涉及公司内部的代码&#xff0c;没法公开发布。 这次遇到了一个项目&#xff0c;用的…

Java后端初开-->架构师学习路线!无偿分享!让你少走弯路

由于平台篇幅原因&#xff0c;很多java面试资料内容展示不了&#xff0c;需要的java面试宝典的伙伴们转发文章关注后&#xff0c;扫描下方二维码免费获取:

FFplay:FFmpeg中的多媒体播放器

&#x1f60e; 作者介绍&#xff1a;欢迎来到我的主页&#x1f448;&#xff0c;我是程序员行者孙&#xff0c;一个热爱分享技术的制能工人。计算机本硕&#xff0c;人工制能研究生。公众号&#xff1a;AI Sun&#xff08;领取大厂面经等资料&#xff09;&#xff0c;欢迎加我的…

【FANUC】发那科机器人ROBOGUIDE安装教程(含安装包)

&#x1f449;博__主&#x1f448;&#xff1a;米码收割机 &#x1f449;技__能&#x1f448;&#xff1a;C/Python语言 &#x1f449;公众号&#x1f448;&#xff1a;测试开发自动化【获取源码商业合作】 &#x1f449;荣__誉&#x1f448;&#xff1a;阿里云博客专家博主、5…

基于Debian用户安装星火商店

星火商店下载地址&#xff1a;https://www.spark-app.store/ 本文章我以kali linux来做示范 注:基本debian的linux包括ubuntu,mint linux,kali linux,Pop!_OS,deepin等等 1.点击下载最新版本 2.点击下载 3.点击开始下载&#xff08;它会自动跳转网页&#xff09; 4.选择要下载…

告别啃书难,4款pdf翻译成中文神器在手,阅读起来so easy

在这个快节奏的时代&#xff0c;当我们遇到外文的PDF文档时&#xff0c;能不能快速翻译成中文变得非常重要。为了帮大家解决这个问题&#xff0c;我找来了四款专门用于把pdf翻译成中文的工具。这些工具操作起来很简单&#xff0c;翻译的质量也很高&#xff0c;能帮我们大大提高…