【并发编程十一】c++线程同步——future

news2024/11/28 6:28:29

【并发编程十一】c++线程同步——future

  • 一、互斥
  • 二、条件变量
  • 三、future
    • 1、promise
      • 1.1、子线程设值,主线程获取
      • 1.2、主线程设置值,子线程获取
      • 1.3、shared_future
    • 2、async
      • 2.1、不开新线程的async
      • 2.2、开新线程的async
    • 3、packaged_task
      • 3.1、不使用bind
      • 3.2、提前指定参数
      • 3.3、bind
    • 4、shared_future
  • 四、信号量

简介:
本篇文章,我们详细的介绍下c++标准库提供的线程同步方法——future。

一、互斥

参见【并发编程九】c++线程同步——互斥(mutex)

二、条件变量

参见【并发编程十】c++线程同步——条件变量(condition_variable)

三、future

类模板 std::future 提供访问异步操作结果的机制:

  • (通过std::asyncstd::packaged_taskstd::promise 创建的)异步操作能提供一个 std::future 对象给该异步操作的创建者。
  • 然后,异步操作的创建者能用各种方法查询、等待或从 std::future 提取值。若异步操作仍未提供值,则这些方法可能阻塞。
  • 异步操作准备好发送结果给创建者时,它能通过修改链接到创建者的 std::future 的共享状态(例如 std::promise::set_value )进行。

注意, std::future 所引用的共享状态不与另一异步返回对象共享(与 std::shared_future 相反)。

在这里插入图片描述

1、promise

  • 类模板 std::promise 提供存储值或异常的设施,之后通过 std::promise 对象所创建的 std::future 对象异步获得结果。注意 std::promise 只应当使用一次。

备注:简单来说,就是以下过程

  • 1、把promis和future绑定。
  • 2、promise设置值后,
  • 3、future等待,直到获取值。

1.1、子线程设值,主线程获取

  • demo
#include <iostream>
#include <future>
#include <thread>
using namespace std;

void task(int a, int b, promise<int>& p)
{
    p.set_value(a + b);
}
int main()
{
    // 把promise和future做关联
    promise<int> p;
    future<int> f=p.get_future();

    thread task1(task,1,2,ref(p));

    //do somesthing

    //get promise value
    f.wait();
    cout << "return value is " << f.get() << '\n';//只能get一次。

    task1.join();
}
  • 输出

在这里插入图片描述

1.2、主线程设置值,子线程获取

  • demo
#include <iostream>
#include <future>
#include <thread>
using namespace std;

void task(int a, future<int>& b, promise<int>& p)
{
    p.set_value(a + b.get());
}
int main()
{
   // 把promise和future做关联
    promise<int> p_ret;
    future<int> f_ret=p_ret.get_future();

    promise<int> p_in;
    future<int> f_in = p_in.get_future();

    thread task1(task,1,ref(f_in),ref(p_ret));

    //do somesthing
    //...
    p_in.set_value(3);

    //get promise value
    f_ret.wait();
    cout << "return value is " << f_ret.get() << '\n';//只能get一次。

    task1.join();
}
  • 输出

在这里插入图片描述

1.3、shared_future

2、async

异步运行一个函数(有可能在新线程中执行),并返回保有其结果的 std::future.

2.1、不开新线程的async

  • demo
#include <iostream>
#include <future>
#include <thread>
using namespace std;

int task(int a, int b)
{
   return a + b;
}


int main()
{
    // 把async和future做关联
    future<int> f = async(task, 1, 5);

    //get future value
    f.wait();
    cout << "return value is " << f.get()<< '\n';
}
  • 输出

在这里插入图片描述

2.2、开新线程的async

  • launch::async意思是创建新的线程。
  • launch::deferred和不传默认参数是一样的,相当于延时调用。
#include <iostream>
#include <future>
#include <thread>
using namespace std;

int task(int a, int b)
{
   return a + b;
}


int main()
{
    // 把async和future做关联
    future<int> f = async(launch::async,task, 1, 5);

    //get future value
    f.wait();
    cout << "return value is " << f.get()<< '\n';
}

输出结果和不开线程一样的

3、packaged_task

  • 打包一个函数,存储其返回值以进行异步获取

3.1、不使用bind

  • demo
#include <iostream>
#include <future>
#include <thread>
using namespace std;

int task(int a, int b)
{
   return a + b;
}

int main()
{
    // 调用packaged_task的构造函数,返回值和两个参数都是int类型,
    packaged_task<int(int, int)> t(task);
    //执行
    t(5,5);

    // 把packaged_task和future做关联
    future<int> f = t.get_future();

    //获取返回值的结果
    f.wait();
    cout << "return value is " << f.get()<< '\n';
}

输出

在这里插入图片描述

3.2、提前指定参数

#include <iostream>
#include <future>
#include <thread>
using namespace std;

int task(int a, int b)
{
   return a + b;
}

int main()
{
    // 调用packaged_task的构造函数,返回值和两个参数都是int类型,
    packaged_task<int()> t(std::bind(task,11,12));
    //执行
    t();

    // 把packaged_task和future做关联
    future<int> result = t.get_future();

    //获取返回值的结果
    result.wait();
    cout << "return value is " << result.get()<< '\n';
}
  • 输出

在这里插入图片描述

3.3、bind

bind返回参数为std::function

  • demo
#include <iostream>
#include <future>
#include <thread>
using namespace std;

int task(int a, int b)
{
   return a + b;
}

int main()
{
    // bind返回值为std::function,
    auto a = bind(task, 11, 14);
    //执行
    int result = a();

    cout << "return value is " << result << '\n';
}
  • 输出

在这里插入图片描述

备注:既然bind就可以获取结果,为何还要用packaged_task,当然是因为future啊。

4、shared_future

  • future只能get一次,那如果我们想用使用多次的get呢?———答:使用shared_future。
  • 网上的例子基本都是shared_future和async放在一起使用。
  • 网上并没有shared_future和promise一起使用的例子,所以我们写下后者的例子demo.
#include <iostream>
#include <future>
#include <thread>
using namespace std;

mutex mtx;

void task(int a, shared_future<int>& b, promise<int>& p)
{
    p.set_value(2);
    b.wait();
    int bb = b.get();
    lock_guard<mutex> guard(mtx);
    cout << "task b =" << b.get()<<endl;
}
int main()
{
    // 把promise和future做关联
    promise<int> p_ret_1,p_ret_2;

    future<int> f1 = p_ret_1.get_future();
    future<int> f2 = p_ret_2.get_future();

    promise<int> p_in;
    shared_future<int> s_f = p_in.get_future();

    thread task1(task, 1, ref(s_f), ref(p_ret_1));
    thread task2(task, 2, ref(s_f), ref(p_ret_2));

    //do somesthing
    f1.wait();
    f2.wait();
    //...
    p_in.set_value(3);

    //get promise value
    {
        lock_guard<mutex> guard(mtx);
        cout << "main() return value is " << f1.get() << '\n';//只能get一次。
        cout << "main() return value is " << f2.get() << '\n';//只能get一次。
    }

    task1.join();
    task2.join();
}
  • 输出

在这里插入图片描述

参考:
1、https://www.apiref.com/cpp-zh/cpp/thread.html
2、https://en.cppreference.com/w/cpp/thread
3、书籍《c++服务器开发精髓》——张远龙

四、信号量

  • 参见【并发编程十二】c++20线程同步——信号量(semaphore)

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

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

相关文章

Kafka-概述

一、Kafka是什么 1.定义 Apache Kafka 是一款开源的消息引擎系统。 消息引擎系统是一组规范。企业利用这组规范在不同系统之间传递语义准确的消息&#xff0c;实现松耦合的异步式数据传递。 二、消息队列的使用场景 传统消息队列的应用场景包括 缓存/削峰、解耦、异步通信 …

vue(透传属性,$attrs)

官方文档 https://cn.vuejs.org/guide/components/attrs.html 案例 <FirstLevel class"attr-test-class" name"zs" age"18"></FirstLevel>FirstLevel组件没有用props去申明name和age&#xff0c;所以这两个属性会透视传递。 <…

RT-Thread系列--组件初始化

一、目的RT-Thread里面有个特别有意思的软件设计叫做组件自动初始化。有些小伙伴可能是第一次听说&#xff0c;所以这边我解释一下&#xff0c;请看下面的代码片段static void clock_init() {// 时钟初始化 } static void uart_init() {// 串口初始化 } static void i2c_init()…

SpringBoot自定义拦截器

&#x1f341;博客主页&#xff1a;&#x1f449;不会压弯的小飞侠 ✨欢迎关注&#xff1a;&#x1f449;点赞&#x1f44d;收藏⭐留言✒ ✨系列专栏&#xff1a;&#x1f449;SpringBoot专栏 &#x1f525;欢迎大佬指正&#xff0c;一起学习&#xff01;一起加油&#xff01; …

JavaScript 浏览器的重排和重绘

文章目录JavaScript 浏览器的重排和重绘概述浏览器解析过程重排重绘优化将多次改变样式的属性操作合并为一次需要多次重排的元素设置为绝对定位减少DOM操作复杂元素处理先设置display为none处理完后再显示缓存频繁操作的属性减少使用table布局使用事件委托绑定事件处理程序利用…

上海亚商投顾:沪指重返3200点 牛市旗手回归!

上海亚商投顾前言&#xff1a;无惧大盘涨跌&#xff0c;解密龙虎榜资金&#xff0c;跟踪一线游资和机构资金动向&#xff0c;识别短期热点和强势个股。市场情绪三大指数今日继续走强&#xff0c;沪指重返3200点上方&#xff0c;创业板指午后一度涨近3%&#xff0c;随后涨幅有所…

2023.1. Stimulsoft 报告和仪表板的新版本:Crack

2023.1. Stimulsoft 报告和仪表板的新版本。 发布时间&#xff1a;2022 年 12 月 9 日 我们很高兴地宣布发布 Stimulsoft Reports and Dashboards 2023.1 版&#xff01;我们为 .NET Core 组件添加了对Razor Pages的支持&#xff0c;为PHP和Blazor平台更新了组件。此外&#x…

【Linux】基础:进程间通信

【Linux】基础&#xff1a;进程间通信 摘要&#xff1a;本文主要介绍进程间通信的基础知识&#xff0c;首先将会对进程间通信进行简单概述&#xff0c;其中包括本质目的和方法分类。再介绍对于方法的实现过程&#xff0c;其中有三大类方法&#xff08;管道、System V、POSIX&am…

Kotlin 中变量,类型,表达式,函数详解

博主前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住也分享一下给大家 &#x1f449;点击跳转到教程 一、变量&#xff0c;编译时变量 1、要声明可修改变量&#xff0c;使用var关键字。 2、要声明只读变量&#xff0c;使用…

35岁高龄程序员的 4 条出路,提早布局,避免出局!

目录 一、40岁回首往事&#xff1a;自己竟没有任何核心优势二、公司遇到危机时40岁大龄程序员会怎么样三、适合大龄程序员的几条职业发展路线四、最后的寄语 这篇文章&#xff0c;给大家聊聊Java工程师的职业发展规划的一些思考&#xff0c;同时也给不少20多岁、30多岁&#…

Spark 运行架构

文章目录Spark 运行架构一、运行架构二、核心组件1、Driver2、Executor3、Master & Worker4、ApplicationMaster三、核心概念1、Exuecutor 和 Core2、并行度&#xff08;Parallelism&#xff09;3、有向无环图&#xff08;DAG&#xff09;4、提交流程Yarn Client 模式Spark…

Spring Cloud Gateway(黑马springcloud笔记)

Gateway 目录Gateway一、为什么需要网关二、gateway入门三、断言工厂四、过滤器工厂五、全局过滤1. 实现2. 过滤器执行顺序六、跨域问题一、为什么需要网关 不能让外部能够直接访问微服务&#xff0c;而是需要通过网关访问&#xff1a; 网关的作用&#xff1a; 身份认证和权限…

数据结构与算法基础(王卓)(8):线性表的应用(并集和有序表合并)

PPT&#xff1a;第二章P173&#xff1b; 并集集合&#xff1a;线性表的合并&#xff08;无需有序&#xff0c;不能重复&#xff09; 线性表&#xff1a; Status Union(Sqlist& A, Sqlist& B)//并集 {int len_A A.length;int len_B B.length;for (int i 1; i < …

研究生如何能(较快)找出某领域(去噪)已有算法的创新点或者引入其他领域的新算法?

广义上说&#xff0c;滤波就是给不同的信号分量分配不同的权重&#xff0c;较为复杂的维纳滤波, 是根据信号的统计量设计权重。狭义上说&#xff0c;降噪/去噪&#xff0c;可以看成滤波的一种。降噪的目的在于突出信号本身而抑制噪声影响。从这个角度&#xff0c;降噪就是给信号…

C/C++ 调用规则

平栈&#xff1a;清理参数对调用栈的操作步骤&#xff1a;参数传递三种调用约定&#xff1a;cdecl &#xff08;C调用约定&#xff09;:从右往左传参&#xff0c;参数通过栈传递&#xff0c;调用方(caller)负责平参&#xff08;支持类似printf的不定参&#xff09;stdcall (标准…

hadoop简介

文章目录1&#xff1a;hadoop简介2&#xff1a;Hadoop系统2.1&#xff1a;hadoop架构1&#xff1a;MapReduce2&#xff1a;YARN架构3&#xff1a;HDFS2.2&#xff1a;HDFS、YARN、MapReduce三者关系1&#xff1a;hadoop简介 Hadoop是一个由Apache基金会所开发的分布式系统基础…

如何快速删除CSV、Excel、Markdown表格的重复行?

如果你正在使用 CSV、Excel 或 Markdown 表格&#xff0c;你可能会遇到重复行的问题。这可能是因为你手动输入了重复的数据&#xff0c;或者是因为你从其他源导入了重复的数据。无论原因是什么&#xff0c;删除重复行是一项重要的数据清理任务。本文将向你展示如何使用几种不同…

RESTful的风格提倡 URL 地址使用统一的风格设计

RESTful概念实现REST&#xff1a;Representational State Transfer&#xff0c;表现层资源状态转移。资源&#xff1a;资源是一种看待服务器的方式&#xff0c;即&#xff0c;将服务器看作是由很多离散的资源组成。每个资源是服务器上一个可命名的抽象概念。资源的表述资源的表…

nnUNet 训练 AMOS22数据集 Task216(抽丝剥茧指令+原理篇)

环境准备篇 安装hiddenlayer&#xff08;用来生成什么网络拓扑图&#xff1f;管他呢&#xff0c;装吧&#xff09; pip install --upgrade githttps://github.com/nanohanno/hiddenlayer.gitbugfix/get_trace_graph#egghiddenlayer 安装环境&#xff0c;由于服务器已经装好py…

网络安全日益严峻下计算机主机加固的意义

​ 近年来&#xff0c;计算机以及互联网应用在中国得到普及和发展&#xff0c;已经深入到社会每个角落&#xff0c;政府&#xff0c;经济&#xff0c;军事&#xff0c;社会&#xff0c;文化和人们生活等各方面都越来越依赖于计算机和网络&#xff0c;电子政务&#xff0c;无纸办…