DoubleLi

qq: 517712484 wx: ldbgliet

  博客园 :: 首页 :: 博问 :: 闪存 :: 新随笔 :: 联系 :: 订阅 订阅 :: 管理 ::
  4737 随笔 :: 2 文章 :: 542 评论 :: 1615万 阅读
< 2025年3月 >
23 24 25 26 27 28 1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30 31 1 2 3 4 5

 

 

简介:
本篇文章,我们详细的介绍下c++标准库提供的线程同步方法中的第3个——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();
}
  • 输出

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++服务器开发精髓》——张远龙

四、信号量

 
posted on   DoubleLi  阅读(268)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!
历史上的今天:
2014-03-16 source code analyzer 功能强大的C/C++源代码分析软件 Celerity CRACK 破解版
2014-03-16 分析函数调用关系图(call graph)的几种方法
2014-03-16 用CodeViz绘制函数调用关系图(call graph)
2014-03-16 C++的辅助工具介绍
2013-03-16 位运算中的异或运算 .
2013-03-16 按位与、或、异或等运算方法
2012-03-16 Javascript 对象用法
点击右上角即可分享
微信分享提示