c/c++ 多线程 等待一次性事件 packaged_task用法

多线程 等待一次性事件 packaged_task用法

背景:不是很明白,不知道为了解决什么业务场景,感觉std::asynck可以优雅的搞定一切,一次等待性事件,为什么还有个packaged_task。

用法:和std::async一样,也能够返回std::future,通过调用get_future方法。也可以通过future得到线程的返回值。

特点:

1,是个模板类,模板类型是个方法类型,比如double(int),有一个参数,类型是int,返回值类型是double。

std::packaged_task<double(int)> task(func);//func是个方法,有一个参数,类型是int,返回值类型是double

2,直接执行std::packaged_task的对象task时,不是异步执行,是在原来的线程上阻塞执行,也就是说,只有task执行结束后,后面的代码才能被执行,也就是说不是多线程执行。

std::packaged_task<std::string(int)> task1(call_texi);
std::future<std::string> ft1 = task1.get_future();
task1(100);//task1执行完成后,才能执行下面的打印输出的代码,不是在新的线程里执行task1(100)
std::cout << "111111111111111111111111111111" << std::endl;

3,作为线程的参数时,必须用std::move转成右值,否则编译不过。把task放在线程里后,就是异步执行了。

std::packaged_task<std::string(int)> task1(call_texi);
std::future<std::string> ft1 = task1.get_future();
std::thread t1(std::move(task1), 100);
t1.detach();//task1(100)是异步执行,也就是在新的线程里执行。
std::cout << "111111111111111111111111111111" << std::endl;

4,std::packaged_task的拷贝构造函数是被删除了的,所以std::packaged_task作为函数的参数时,必须用std::move(task),把它转成右值引用。

代码:

#include <deque>
#include <mutex>
#include <future>
#include <thread>
#include <iostream>
#include <unistd.h>
#include <string>
//#include <utility>

std::mutex mut;
std::deque<std::packaged_task<std::string(int)>> tasks;

void manage_tasks(){
  while(true){
    sleep(1);
    //std::cout << "please wait for a moument" << std::endl;
    std::packaged_task<std::string(int)> task;
    {
      std::lock_guard<std::mutex> lg(mut);
      if(tasks.empty()) continue;
      std::cout << "----------------------not empty---------------" << std::endl;
      task = std::move(tasks.front());
      tasks.pop_front();
    }
    task(1);
    //std::string s = task(10);
  }
}

template<typename Call>
std::future<std::string> add_task(Call ca){
  std::cout << "----------------------add_task---------------" << std::endl;
  std::packaged_task<std::string(int)> task(ca);
  std::future<std::string> ret = task.get_future();
  std::lock_guard<std::mutex> lg(mut);
  tasks.push_back(std::move(task));
  return ret;
}

std::string call_texi(int i = 0){
  std::cout << "-------------jiaoche---------------" << std::endl;
  if(i == 1){
    return "aaa";
  }else{
    return "bbb";
  }
}

std::string call_zhuanche(int i){
  std::cout << "zhuanche:" << i << std::endl;
  return std::to_string(i);
}
int main(){

  std::thread background_thread(manage_tasks);
  background_thread.detach();

  std::future<std::string> fut1 = add_task(call_texi);
  std::cout << fut1.get() << std::endl;

  std::future<std::string> fut2 = add_task(call_zhuanche);
  std::cout << fut2.get() << std::endl;

  pthread_exit(NULL);

}

github源代码

编译方法:

g++ -g XXX.cpp -std=c++11 -pthread

运行结果:

----------------------add_task---------------
----------------------not empty---------------
-------------jiaoche---------------
aaa
----------------------add_task---------------
----------------------not empty---------------
zhuanche:1
1

代码分析:在队列里保存std::packaged_task,启动一个后台线程background_thread,上锁,监视队列里是否有了新的task,有了新的task,就取出来用右值赋值的方式,然后出队这个task,解锁。执行这个task。

迷惑点:

  • add_task的调用时点,是可以知道传递什么参数的,但是调用add_task时,由于语法的限制不能够把参数传递给call_zhuanche方法或者call_taxi方法,只有在manage_tasks方法里调用task方法时,才能够传递参数,可是在这个时点,参数从哪里来???求大神指点!!!

c/c++ 学习互助QQ群:877684253

本人微信:xiaoshitou5854

原文地址:https://www.cnblogs.com/xiaoshiwang/p/10014219.html

时间: 2024-07-31 23:05:59

c/c++ 多线程 等待一次性事件 packaged_task用法的相关文章

c/c++ 多线程 等待一次性事件 std::promise用法

多线程 等待一次性事件 std::promise用法 背景:不是很明白,不知道为了解决什么业务场景,感觉std::async可以优雅的搞定一切的一次等待性事件,为什么还有个std::promise. 用法:和std::async一样,也能够返回std::future,通过调用get_future方法.也可以通过future得到线程的返回值. 特点: 1,是个模板类,模板类型是个方法类型,比如double(int),有一个参数,类型是int,返回值类型是double. std::promise<i

c/c++ 多线程 等待一次性事件 异常处理

多线程 等待一次性事件 异常处理 背景:假设某个future在等待另一个线程结束,但是在被future等待的线程里发生了异常(throw一个异常A),这时怎么处理. 结果:假设发生了上面的场景,则在调用future的get方法时,就会得到被future等待的线程抛出的异常A. 3种情况: 1,std::async 2,std::packaged_task 3,std::promise,知道发生异常了,可以不调用set_value,而是调用set_exception(std::current_ex

[C++11 并发编程] 13 使用期望等待一次性事件

C++标准库使用期望(future)来支持一次性事件的等待.要等待某种一次性事件的线程可以获取一个代表该该事件的期望.这个线程可以每隔一段事件周期性的查询这个期望.此外,这个线程也可以继续做其它的处理,直到需要等待这个一次性事件才被挂起.通过期望还可以可以传递数据. C++标准库提供了两种期望unique future(std::future<>)和shared futures(std::shared_future<>),都声明在<future>库头文件中.std::f

同步并发操作之等待一次性事件

有时候需要用一些后台线程来完成计算,这些计算往往都是一次性的,线程计算完后便结束.这时候可以使用条件变量,但是有点浪费,我们只需要获取一次结果.C++标准库中有头文件<future>,很形象"未来",获取未来计算的结果. 使用std::async来启动一个异步任务.用std::future对象来存储异步任务返回的结果,这个对象存储结果.当我们需要结果时,只需调用get()方法.这时如果还没计算完毕,当前线程会阻塞. #include<future> #inclu

c/c++ 多线程 多个线程等待同一个线程的一次性事件

多线程 多个线程等待一个线程的一次性事件 背景:从多个线程访问同一个std::future,也就是多个线程都在等待同一个线程的结果,这时怎么处理. 办法:由于std::future只能被调用一次get方法,也就是只能被某一个线程等待(同步)一次,不支持被多个线程等待.所以std::sharted_future,就应运而生了. 特点:std::sharted_future可以被复制,std::future是不可以的被复制的. std::sharted_future的3种创建方式(fut为std::

iOS开发多线程篇—GCD的常见用法

iOS开发多线程篇—GCD的常见用法 一.延迟执行 1.介绍 iOS常见的延时执行有2种方式 (1)调用NSObject的方法 [self performSelector:@selector(run) withObject:nil afterDelay:2.0]; // 2秒后再调用self的run方法 (2)使用GCD函数 dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2.0 * NSEC_PER_SEC)), dispat

c#多线程中Lock()关键字的用法小结

本篇文章主要是对c#多线程中Lock()关键字的用法进行了详细的总结介绍,需要的朋友可以过来参考下,希望对大家有所帮助 本文介绍C# lock关键字,C#提供了一个关键字lock,它可以把一段代码定义为互斥段(critical section),互斥段在一个时刻内只允许一个线程进入执行,而其他线程必须等待. 每个线程都有自己的资源,但是代码区是共享的,即每个线程都可以执行相同的函数.这可能带来的问题就是几个线程同时执行一个函数,导致数据的混乱,产生不可预料的结果,因此我们必须避免这种情况的发生.

关于gevent的协程间通信及队列和事件event用法

前言: 今天就写点gevent的高级点的用法,对于我来说 这些也是常用的gevent模块. gevent的AsyncResutl模块的用途,看字眼的意思是一个异步的任务的结果. 其实官方的说法也让人有些发蒙.  其实说白了就是协程间的通信,我是老板,让大哥和小弟同事去收账,小弟做完了后,会等大哥来问话. 如果小弟没有完成,还在做着事情,那大哥会在一个时间里,等待小弟返回结果.一直等 ! 在实战中这个就很有意思了.   我们同时做一个事情,但是我们又需要互相的帮助,或者是互相的通信.  这个时候就

js事件监听器用法实例详解

本文实例讲述了js事件监听器用法.分享给大家供大家参考.具体分析如下: 1.当同一个对象使用.onclick的写法触发多个方法的时候,后一个方法会把前一个方法覆盖掉,也就是说,在对象的onclick事件发生时,只会执行最后绑定的方法.而用事件监听则不会有覆盖的现象,每个绑定的事件都会被执行.如下: window.onload = function(){  var btn = document.getElementById("yuanEvent");  btn.onclick = fun