1.function和bind

这两个函数需要包含头文件#inlude<functional>。

std::function是一种封装函数的工具或者说方法。std::function封装包普通函数、Lambda表达式、函数指针、以及其它函数对象等。std::function功能比函数指针更多,也更安全。

下面是function的使用示例:

#include <thread>
#include <functional>
#include <iostream>int func1(int& a,int b)
{return a + b;
}int main()
{int a = 3;int b = 1;std::function<int(int&,int)> f;f = func1;std::cout << f(a,b) << '\n';return 0;
}

上面展示了function是如何包装函数的。除此之外它还可以和bind结合绑定参数,如下:

#include <thread>
#include <functional>
#include <iostream>int func1(int& a,int b)
{return a + b;
}int main()
{int a = 3;int b = 1;//bind将a,b绑定到了func1里,因此f是int()而非(int(int&,int))std::function<int()> f;f = std::bind(func1, std::ref(a), b);std::cout << f() << '\n';return 0;
}

bind相当于将参数提前绑定到函数里,此后调用无需参数。f可以理解成下面那个样子:

int func1(int& a,int b)
{return a + b;
}std::function<int()> f;
f = std::bind(func1, std::ref(a), b);此时的f可以看成下面那样
int f()
{int& a1=a;int b1=b;return a1+b1;
}

我们可以采取这种方式提前将函数参数传入,这种方式可以更方便的回调,如下面伪代码

int func1(int& a,int b) {}
int func2(int a,int b,int c) {}void func(std::function<int()> f)
{f();
}std::function<int()> f1;
std::function<int()> f2;
f1 = std::bind(func1, std::ref(a), b);
f2 = std::bind(func1, a, b, c);

可以看出这种方式封装的函数作回调函数时无需传递参数,使得需要调用该回调函数的func无需考虑到多种情况设置参数。

2.async和future

使用这两个函数需要包含头文件#include<future>

2.1 async和future的简单用法:

async会返回一个future类型的数据,future的作用是获得异步操作的结果,无需使用全局变量。先看看使用方法:

#include <thread>
#include <functional>
#include <future>
#include <unistd.h>
#include <iostream>int func1(int& a,int b)
{return a + b;
}void func2(int& a)
{for (int i = 0; i < 10; i++){a++;usleep(500 * 1000);}
}int main()
{int a = 3;int b = 1;std::future<void> f1 = std::async(func2, std::ref(a));f1.wait();std::cout << a << '\n';std::future<int> f = std::async(func1, std::ref(a), b);std::cout << f.get() << '\n';return 0;
}

如上代码执行结果如下:

可以看到主函数第一部分并没有直接输出处于for循环时的a的中间值,而是等for循环结束才输出a的值。可以看出f1.wait()函数等到f1结束才进行后面代码。在主函数第二部分我们也发现我们可以直接输出func1的返回值。

2.2 async的参数:

从2.1的示例程序看async的参数比较好理解,后面跟随的时函数名和参数。但实际上我们看一下async此时的源码:

template<typename _Fn, typename... _Args>inline future<__async_result_of<_Fn, _Args...>>async(_Fn&& __fn, _Args&&... __args){return std::async(launch::async|launch::deferred,std::forward<_Fn>(__fn),std::forward<_Args>(__args)...);}

可以看出它返回的async有一个参数“launch::async|launch::deferred”。实际上async在函数名和参数之前还有一个参数,该参数可选为std::launch::async或std::launch::deferred。

std::launch::async相当于开辟一个新的线程执行函数,如下代码:

#include <thread>
#include <functional>
#include <future>
#include <unistd.h>
#include <iostream>void func(int& a)
{for (int i = 0; i < 10; i++){a++;std::cout << i << ' ';}
}int main()
{int a = 3;std::future<void> f1 = std::async(std::launch::async, func, std::ref(a));usleep(1000 * 1000);std::cout << std::endl << "ok" << std::endl;f1.wait();return 0;
}

输出结果如下:

可以看出主线程在usleep过程中func已经执行完毕,因此可以猜测确实开启了一个新线程。我们再采取打出线程号的方式:

#include <thread>
#include <functional>
#include <future>
#include <unistd.h>
#include <iostream>void func(int& a)
{for (int i = 0; i < 10; i++){a++;/*std::cout << i << ' ';*/}std::cout << std::this_thread::get_id() << '\n';
}int main()
{int a = 3;int b = 1;std::cout<<std::this_thread::get_id()<<'\n';std::future<void> f1 = std::async(std::launch::async,func, std::ref(a));usleep(1000 * 1000);//std::cout << std::endl << "ok" << std::endl;f1.wait();return 0;
}

结果如下:

可以发现线程号并不一样,到此可以判断是开启了一个新的线程。

第一个参数为std::launch::deferred时系统不会开启一个新的线程,而是会在调用f1.wait()或f1.get()时在本线程调用,代码如下:

#include <thread>
#include <functional>
#include <future>
#include <unistd.h>
#include <iostream>void func(int& a)
{for (int i = 0; i < 10; i++){a++;/*std::cout << i << ' ';*/}std::cout << std::this_thread::get_id() << '\n';
}int main()
{int a = 3;std::cout<<std::this_thread::get_id()<<'\n';std::future<void> f1 = std::async(std::launch::deferred,func, std::ref(a));usleep(1000 * 1000);//std::cout << std::endl << "ok" << std::endl;f1.wait();return 0;
}

结果如下:

可以看出此时并未开启新的线程。

如果不加参数那么等效于第一个参数为launch::async|launch::deferred,此时是否开辟新的线程决于系统的负载,我们无法控制。

3.packaged_task

pacakaged_task需要包含头文件#include<future>

3.1 packaged_task用法:

packaged_task也是一种封装函数的方式,用法的伪代码如下:

void func(int& a) {}int a(0);
std::packaged_task < void(int&) > p1(func);
p1(a);std::packaged_task < void() > p2(std::bind(func, std::ref(a)));
p2();

可以看出packaged_task可以封装函数,而且也支持提前传入参数。但是packaged_task封装的函数无法获得返回值,即便封装的是int或者其它有返回值类型函数。我们看一下packaged_task的operator()源码:

// Executionvoidoperator()(_ArgTypes... __args){__future_base::_State_base::_S_check(_M_state);_M_state->_M_run(std::forward<_ArgTypes>(__args)...);}

无论封装的函数是什么类型,调用operator()时都是void类型,因此我们无法像普通函数和std::function一样直接得到返回值。那可能有人要问有了function为什么还要无法直接获得返回值的packaged_task ?实际上当使用pacakaged_task绑定一个函数时,为这个函数建立了一个future类型,我们可以拿到future类型来得到返回值,伪代码如下:

std::packaged_task < int() > p1(std::bind(func, std::ref(a)));
p1();
std::cout << p1.get_future().get();

这样可以获得返回值。

从它可以返回一个future可以看出pacakaged_task封装的对象可以实现异步。

3.2 packaged_task在多线程:

我们先看下列代码:

#include <thread>
#include <functional>
#include <future>
#include <unistd.h>
#include <iostream>int func(int& a)
{for (int i = 0; i < 10; i++){a++;/*std::cout << i << ' ';*/}std::cout << std::this_thread::get_id() << '\n';return 0;
}int main()
{int a = 3;std::cout<<std::this_thread::get_id()<<'\n';std::packaged_task < int() > p1(std::bind(func, std::ref(a)));auto f1 = p1.get_future();std::thread t1(std::move(p1));usleep(1000 * 1000);f1.wait();return 0;
}

结果如下:

可以发现p1可以用在其它线程,并且可以通过get_future得到返回值或者调用wait实现线程同步。

和std::function相比packaged_task可以在多线程中使用并且异步获得返回值。

与std::async相比我们发现async绑定函数(launch::async方式)后会立即执行,而此种方式绑定的函数我们可以自由选择执行的时机,使得我们使用时可以更灵活。

C++function,future,packaged_task相关推荐

  1. C++多线程std::async、std::future、std::packaged_task、std::promise

    std::async std::async用于创建异步任务,实际上就是创建一个线程执行相应任务,默认立即开始执行. std::async就是异步编程的高级封装,std::async的操作,其实相当于封 ...

  2. C++11 并发指南四(future 详解二 std::packaged_task 介绍)

    上一讲<C++11 并发指南四(<future> 详解一 std::promise 介绍)>主要介绍了 <future> 头文件中的 std::promise 类, ...

  3. C++async、future、packaged_task、promise的使用

    对线程又有了深刻的认识,以前写的线程基本都是同步线程,而自从学习了muduo网络库更知道要用异步的思想去处理问题,因为有时候同步是必须的,但有的时候同步会造成本不必要的浪费,所以也适当的用异步操作来代 ...

  4. C++11中std::packaged_task的使用

    C++11中的std::packaged_task是个模板类.std::packaged_task包装任何可调用目标(函数.lambda表达式.bind表达式.函数对象)以便它可以被异步调用.它的返回 ...

  5. C++11多线程之 std::packaged_task

    简介 先给出官网的一个地址:http://www.cplusplus.com/reference/future/packaged_task/?kw=packaged_task 个人认为,相当于一个装饰 ...

  6. C语言中task的用法,C++11中std::packaged_task的使用详解

    C++11中的std::packaged_task是个模板类.std::packaged_task包装任何可调用目标(函数.lambda表达式.bind表达式.函数对象)以便它可以被异步调用.它的返回 ...

  7. future promise java_第四章 Future和Promise

    Netty是一个异步网络处理框架,在实现中大量使用了Future机制,并在Java自带Future的基础上,增加了Promise机制.这两者的目的都是使异步编程更加方便使用.在阅读源码之前,我们需要对 ...

  8. C++11 多线程之 packaged_task

    packaged_task是什么? template< class R, class ...Args > class packaged_task< fn(Args...)>; ...

  9. 异步编程-Future

    Future可以说是在Dart异步编程中随处可见,比如一个网络请求返回的是Future对象,或者访问一个SharedPreferences返回一个Future对象等等.异步操作可以让你的程序在等待一个 ...

最新文章

  1. delphi自定义事件处理
  2. python面向对象编程 Object-Oriented
  3. 经典的异或题:只出现一次的数字
  4. 脚本类恶意程序分析技巧汇总
  5. 四大算法解决最短路径问题(Dijkstra+Bellman-ford+SPFA+Floyd)
  6. 测试电梯的测试用例_【转】电梯功能的测试用例和测试方案
  7. [USACO]地震 (二分答案+最优比率生成树详解)
  8. 什么是自愈环网光端机?
  9. java集合清空_java 集合删除数据
  10. linux哪个系统能编译固件,rk3328编译Linux固件
  11. rnn 简要_注重文化的简要招聘指南
  12. Java分代垃圾回收机制:年轻代/年老代/持久代(转)
  13. 使用内存映射提高BufferedRandoAccessFile性能(测试可用)
  14. 区块链:5、匿名性和隐私性
  15. 对称矩阵(MIT课程)
  16. LaTeX排版学习资源汇总
  17. [机缘参悟-84]:读《心若菩提 - 曹德旺》有感
  18. 【互联网及其应用】第7章计算机网络安全及管理技术
  19. 用turtle画美国队长盾牌
  20. 第2章 蓝牙降噪耳机测试维度

热门文章

  1. 阿里巴巴的AI价值观,以及“ET大脑”战略
  2. vue中控制台报错[WDS] Disconnected的解决办法
  3. PDF裁剪页面及调整页面大小的方法
  4. 《拆掉思维里的墙》简评和部分摘录
  5. leet415字符串相加
  6. SQLDBX找不到服务器 no server found
  7. 全面的IE兼容性调试问题
  8. jQuery实现可移动(draggable)和可缩放(sizable)网页元素
  9. MFC中通过SendMessage修改Edit控件的文本
  10. 键盘输入平方(m²)或立方(m³)等特殊字符