1、异步操作

  C++11提供了异步操作相关的类,std::future、std::promise和std::package_task。std::future作为异步结果的传输通道,方便的获取线程函数的返回值;std::promise用来包装一个值,将数据和future绑定起来,方便线程赋值;std::pack_age用来包装一个可调用对象,将函数和future绑定起来,以便异步调用。

1.1 std::future

  c11中的线程使我们创建和使用线程非常方便,但是当我们想要得到线程函数的执行结果是比较麻烦的,不能直接通过thread.join()来得到结果,需要定义一个变量,在线程里面进行赋值,然后执行join来得到结果。

  所以,thread库提供了future来访问异步操作的结果,因为是等待线程执行完,在未来获取,所以被成为future,future提供了获取异步操作结果的通道,可以通过同步等待来获取操作结果,并可以查询future的状态来获取异步操作的结果。

  future的状态:

  Deferred,异步操作还未开始;
  Ready,异步操作已经完成;
  Timeout,异步操作超时。

 //查询状态
std::future_status status;
do
{
status = future.wait_for(std::chrono::seconds());
if(status == std::future_status::deferred)
{
//do sommething when deferred
}
else if(status == std::future_status::ready)
{
//do sommething when ready
}
else
{
//do sommething when timeout
}
}while(status != std::future_status::ready)

   获取future有三种方式:get,wait,wait_for,其中get等待异步操作结束并返回结果,wait只是等待异步操作完成,没有返回值;wait_for是超时等待返回结果。

1.2 std::promise

  std::promise可以协助线程赋值,将数据与future绑定起来,为获取线程中某个值提供便利,在线程函数外面传进来的promise赋值,线程函数执行完成之后,通过promise绑定的future来获取该值。取值是间接通过promise内部提供的future来获取的。

     std::promise<int> pr;
std::thread t([](std::promise<int> & p){ p.set_value_at_thread_exit(); }, std::ref(pr)); std::future<int> f = pr.get_future();
int i = f.get();
//执行后 i = 9

1.3 std::package_task

  std::package_task包装一个可调用对象的包装类(如function,lambda expression,bind expression,和其它的函数对象),将函数和future绑定起来,以便异步调用,它和promise的区别是,promise绑定的是一个变量,而package_task则是绑定的一个函数。

    std::packaged_task<int()> task([](){ return ; });
std::thread t1(std::ref(task)); std::future<int> f1 = task.get_future();
int i = f1.get();
//执行后 i = 5

1.4 三者关系

  future提供一个访问线程异步操作结果的机制,它和线程是一个级别的,属于最底层。package_task和promise则是内部都有future,promise是包装一个值,而package_task是包装一个操作对象,具体使用哪个要根据实际情况来做区分。

  需要注意的是,future是不可拷贝的,只能移动,shared_future可以拷贝,如果需要放到容器或者其他地方,则需要用到shared_future。

2、线程异步操作std::async

  std::async比std::promise、std::package_task和std::thread更上层,它可以用来直接创建异步的task,异步任务返回的结果保存在future中,当需要获取线程执行的结果,可以通过future.get()来获取,如果不关注异步任务的结果,只是简单的等待任务执行完成,则调用future.wait()即可。

  std::async是更高层次的异步操作,使我们不关心线程创建的内部细节,就能方便的获取线程异步执行的结果,还可以指定线程创建策略,更多的时候应该使用 std::async来创建线程,成为异步操作的首选。

  std::async原型为std::async(std::launch::async | std::launch::deferred,f,args...),第一个参数为线程的创建策略,第二个为线程函数,其他的为线程函数的参数。

  关于创建策略有两种:

  std::launch::async:在调用async就开始创建线程;
  std::launch::deferred:延迟加载的方式创建线程,调用async的时候不创建线程,直到调用了future的get或者wait方法来创建线程。

#include <thread>
#include <iostream>
#include <mutex>
#include <future> int main()
{
std::future<int> f1 = std::async(std::launch::async, [](){ return ; });
std::cout << f1.get() << std::endl; //output 8 std::future<void> f2 = std::async(std::launch::async, [](){ std::cout << << std::endl; });
f2.wait(); //output 8 std::future<int> f3 = std::async(std::launch::async, []()
{
std::this_thread::sleep_for(std::chrono::seconds());
return ;
}); std::cout << "Wating..." << std::endl;
std::future_status status;
do
{
status = f3.wait_for(std::chrono::seconds());
if (status == std::future_status::deferred)
{
std::cout << "deferred." << std::endl;
}
else if (status == std::future_status::timeout)
{
std::cout << "timeout." << std::endl;
}
else
{
std::cout << "ready." << std::endl;
}
} while (status != std::future_status::ready);
std::cout << "result:" << f3.get() << std::endl; return ;
}
//执行结果: Wating...
timeout.
timeout.
ready.
result:

C11线程管理:异步操作的更多相关文章

  1. C11线程管理:条件变量

    1.简介 C11提供另外一种用于等待的同步机制,它可以阻塞一个或者多个线程,直到收到另外一个线程发出的通知或者超时,才会唤醒当前阻塞的线程.条件变量要和互斥量配合起来使用. condition_var ...

  2. C11线程管理:互斥锁

    1.概述 锁类型 c11提供了跨平台的线程同步手段,用来保护多线程同时访问的共享数据. std::mutex,最基本的 Mutex 类,独占的互斥量,不能递归使用. std::time_mutex,带 ...

  3. C11线程管理:线程创建

    1.线程的创建 C11创建线程非常简单,只需要提供线程函数就行,标准库提供线程库,并可以指定线程函数的参数. #include <iostream> #include <thread ...

  4. C11线程管理:原子变量&单调函数

    1.原子变量 C++11提供了原子类型std::atomic<T>,可以使用任意类型作为模板参数,使用原子变量就不需要使用互斥量来保护该变量,用起来更加简洁. 举个例子,如果要做一个计数器 ...

  5. Android线程管理之AsyncTask异步任务

    前言: 前面几篇文章主要学习了线程以及线程池的创建与使用,今天来学习一下AsyncTask异步任务,学习下AsyncTask到底解决了什么问题?然而它有什么弊端?正所谓知己知彼百战百胜嘛! 线程管理相 ...

  6. Android线程管理之ThreadLocal理解及应用场景

    前言: 最近在学习总结Android的动画效果,当学到Android属性动画的时候大致看了下源代码,里面的AnimationHandler存取使用了ThreadLocal,激起了我很大的好奇心以及兴趣 ...

  7. C++ 11 多线程--线程管理

    说到多线程编程,那么就不得不提并行和并发,多线程是实现并发(并行)的一种手段.并行是指两个或多个独立的操作同时进行.注意这里是同时进行,区别于并发,在一个时间段内执行多个操作.在单核时代,多个线程是并 ...

  8. Android线程管理之Thread使用总结

    前言 最近在一直准备总结一下Android上的线程管理,今天先来总结一下Thread使用. 线程管理相关文章地址: Android线程管理之Thread使用总结 Android线程管理之Executo ...

  9. Android线程管理之ExecutorService线程池

    前言: 上篇学习了线程Thread的使用,今天来学习一下线程池ExecutorService. 线程管理相关文章地址: Android线程管理之Thread使用总结 Android线程管理之Execu ...

随机推荐

  1. Android开发第二阶段(3)

    今天:对闹钟代码的按钮事件进行了添加和修改.对监听器的相关应用也有了进一步的了解和深入. 明天:对主界面的代码的优化比如对按钮位置的调节等细节处理.

  2. ASLR/DEP绕过技术概览

    在经典的栈溢出模型中,通过覆盖函数的返回地址来达到控制程序执行流程(EIP寄存器),通常将返回地址覆盖为0x7FFA4512,这个地址是一条JMP ESP指令,在函数返回时就会跳转到这个地址去执行,也 ...

  3. spring重定向与转发

    1.重定向 A,通过ModelAndView以及RedirectView @RequestMapping("/login1.do") public ModelAndView log ...

  4. webgl 初识2

    之前的文章介绍了webgl. 这里进一步精简. WebGL的全部内容就是创建不同的着色器, 向着色器提供数据然后调用gl.drawArrays 或 gl.drawElements 让WebGL调用当前 ...

  5. BZOJ 1189 紧急疏散(二分+最大流)

    求出所有人撤离的最短时间.由于每扇门只能通过一次,所以不能简单用bfs来搞. 显然答案是有单调性的,考虑二分,问题变成了判断时间x所有人能不能撤离. 考虑最大流.对于每扇门,每个时间通过的人数最多为1 ...

  6. var和let使用上的对比

    var和let比较 1. let没有预解析,不存在变量提升.在代码块中,只要let定义变量,在之前使用,都是报错.先定义完再使用. let a = 12; function fn(){ alert(a ...

  7. 【数据库_Postgresql】数据库主键自增长之加序列和不加序列2种方法

    将表的主键进行序列增加之后可以在数据库层面自动主键id增长 方法如下:先建序列,然后建表关联id主键,然后添加语句,不用考虑id主键 DROP SEQUENCE IF EXISTS "pub ...

  8. P2812 校园网络【[USACO]Network of Schools加强版】

    题目背景 浙江省的几所OI强校的神犇发明了一种人工智能,可以AC任何题目,所以他们决定建立一个网络来共享这个软件.但是由于他们脑力劳动过多导致全身无力身体被♂掏♂空,他们来找你帮助他们. 题目描述 共 ...

  9. 2月24日考试——ZYYS

    LSGJ zyys 战队的 CYA 小垃圾,被各位神佬出的题目搞得心态爆炸.于是他模仿了蔡老师给了你两个整数 n 和 m .让你计算字母表大小为 m ,(即可用 m 个字母)长度为 n ,不存在长度至 ...

  10. [SDOI2011]黑白棋 kth - nim游戏

    题面 题面 题解 观察题目,我们可以发现,这个游戏其实就是不断再把对方挤到一边去,也就是黑子不断往左走,白子不断往右走. 因此可以发现,如果将黑白子按顺序两两配对,那么它们中间的距离会不断缩小,且每次 ...