注册 登录  
 加关注
   显示下一条  |  关闭
温馨提示!由于新浪微博认证机制调整,您的新浪微博帐号绑定已过期,请重新绑定!立即重新绑定新浪微博》  |  关闭

还东国的博客

行之苟有恒,久久自芬芳

 
 
 

日志

 
 

C++11及BOOST特性之二十九C++11并行开发之二task和future及相关  

2016-06-02 09:42:05|  分类: C++(VC)编程 |  标签: |举报 |字号 订阅

  下载LOFTER 我的照片书  |

C++11BOOST特性之二十九C++11并行开发之二taskfuture及相关

 

在前面的二十五中,初步谈了一下C++11中的task等新的并行开发方法。这里进一步谈一下相关的方法和使用的场合及注意事项。

这次将把std::future std::shared_futurestd::packaged_task ( std::function 类似) std::promise以及 std::async。都过一次。

std::promise

std::promise为获取线程函数中的某个值提供便利,在线程函数中给外面传进来的promise赋值,当线程函数执行完成之后就可以通过promis获取该值了,值得注意的是取值是间接的通过promise内部提供的future来获取的。它的基本用法:

std::promise<int> pr;

    std::thread t([](std::promise<int>& p){ p.set_value_at_thread_exit(9); },std::ref(pr));

    std::future<int> f = pr.get_future();

    auto r = f.get();

std::packaged_task

std::packaged_task它包装了一个可调用的目标(如function, lambda expression, bind expression, or another function object,以便异步调用,它和promise在某种程度上有点像,promise保存了一个共享状态的值,而packaged_task保存的是一个函数。它的基本用法:

 

std::packaged_task<int()> task([](){ return 7; });

    std::thread t1(std::ref(task));

    std::future<int> f1 = task.get_future();

    auto r1 = f1.get();

 

std::shared_future std::future 类似,但是 std::shared_future 可以拷贝、多个 std::shared_future 可以共享某个共享状态的最终结果(即共享状态的某个值或者异常)shared_future 可以通过某个 std::future 对象隐式转换(参见 std::shared_future 的构造函数),或者通过 std::future::share() 显示转换,无论哪种转换,被转换的那个 std::future 对象都会变为 not-valid.

c++11中提供了async函数可以使我们异步执行相关的逻辑,而不需要手动创建thread。但是如果在一个for循环里依次调用async,而没有创建一个相应对future集合来将asyncfuture收集起来,那么循环里的async虽然是在各自线程里执行的,但却不是异步的。原因在于async内的future临时对象,在析构的时候调用join同步等待,后续的循环却不能继续执行。这个一定要记清楚,防止使用的时候儿犯想当然的错误。

std::async到底有什么用呢? std::async是为了让程序员省心的,它让std::futurestd::promisestd::packaged_task三个对象默契的工作。大概的工作过程是这样的:std::async先将异步操作用std::packaged_task包装起来,然后将异步操作的结果放到std::promise中,这个过程就是创造未来的过程。外面再通过future.get/wait来获取这个未来的结果,这样一来,程序员就不需要太操心std::futurestd::promisestd::packaged_task三个的用法了,std::async已经帮你搞定。

现在来看看std::async的原型async(std::launch::async | std::launch::deferred, f, args...),第一个参数是线程的创建策略,有两种策略,默认的策略是立即创建线程:

std::launch::async:在调用async就开始创建线程。

std::launch::deferred:延迟加载方式创建线程。调用async时不创建线程,直到调用了futureget或者wait时才创建线程。

第二个参数是线程函数,第三个参数是线程函数的参数。

下面举一个线程池的例子:

通常线程池采用模板实现时各线程执行的都是相同类型的任务,若采用packaged_task可以将不同类型的函数对象封转在其内部,每个线程取走一个packaged_task执行,那么线程池执行的任务可以不同。

   下面是一个GUI中一个线程专门接收用户任务并压入任务队列,另一个线程专门执行用户任务

std::mutex m; 

std::deque<std::packaged_task<void()> > tasks; 

bool gui_shutdown_message_received(); 

void get_and_process_gui_message(); 

void gui_thread() 

   while(!gui_shutdown_message_received())//不断获取用户任务 

   { 

      get_and_process_gui_message(); 

      std::packaged_task<void()> task; 

      { 

          std::lock_guard<std::mutex> lk(m); 

          if(tasks.empty()) 

              continue; 

          task=std::move(tasks.front());// 

          tasks.pop_front(); 

      } 

      task(); 

   } 

std::thread gui_bg_thread(gui_thread); 

template<typename Func> 

std::future<void> post_task_for_gui_thread(Func f)//添加任务 

   std::packaged_task<void()> task(f); 

   std::future<void> res=task.get_future(); 

   std::lock_guard<std::mutex> lk(m); 

   tasks.push_back(std::move(task));// 

   return res; 

 

见下列网页资料:

http://www.cnblogs.com/haippy/p/3279565.html

http://www.th7.cn/Program/cp/201601/759174.shtml

http://www.tuicool.com/articles/6j2u2qa

http://www.cnblogs.com/haippy/p/3239248.html

http://blog.csdn.net/liuxuejiang158blog/article/details/17354115

http://www.cnblogs.com/haippy/p/3280643.html

http://www.360doc.com/content/15/0813/11/7591436_491357354.shtml

  评论这张
 
阅读(165)| 评论(0)
推荐 转载

历史上的今天

在LOFTER的更多文章

评论

<#--最新日志,群博日志--> <#--推荐日志--> <#--引用记录--> <#--博主推荐--> <#--随机阅读--> <#--首页推荐--> <#--历史上的今天--> <#--被推荐日志--> <#--上一篇,下一篇--> <#-- 热度 --> <#-- 网易新闻广告 --> <#--右边模块结构--> <#--评论模块结构--> <#--引用模块结构--> <#--博主发起的投票-->
 
 
 
 
 
 
 
 
 
 
 
 
 
 

页脚

网易公司版权所有 ©1997-2017