std::packaged_task() ---C++17 并发编程

std::packaged_task() —C++17 并发编程

std::packaged_task<>连结了future对象与函数(或可调用对象)。

std::packaged_task<>对象在执行任务时,会调用关联的函数(或可调用对象),把返回值保存为future的内部数据,并令future准备就绪。它可作为线程池的构件单元,亦可用于其他任务管理方案。

例如,为各个任务分别创建专属的独立运行的线程,或者在某个特定的后台线程上依次执行全部任务。若一项庞杂的操作能分解为多个子任务,则可把它们分别包装到多个std::packaged_task<>实例之中,再传递给任务调度器或线程池。这就隐藏了细节,使任务抽象化,让调度器得以专注处理std::packaged_task<>实例,无须纠缠于形形色色的任务函数。
std::packaged_task<>是类模板,其模板参数是函数签名(function signature):譬如,void()表示一个函数,不接收参数,也没有返回值;又如,int(std::string&,double*)代表某函数,它接收两个参数并返回int值,其中,第一个参数是非const引用,指向std::string对象,第二个参数是double类型的指针。

假设,我们要构建std::packaged_task<>实例,那么,由于模板参数先行指定了函数签名,因此传入的函数(或可调用对象)必须与之相符,即它应接收指定类型的参数,返回值也必须可以转换为指定类型。
这些类型不必严格匹配,若某函数接收int类型参数并返回float值,我们则可以为其构建std::packaged_task<double(double)>的实例,因为对应的类型可进行隐式转换。
类模板std::packaged_task<>具有成员函数get_future(),它返回std::future<>实例,该future的特化类型取决于函数签名所指定的返回值。
std::packaged_task<>还具备函数调用操作符,它的参数取决于函数签名的参数列表。

std::packaged_task对象是可调用对象,我们可以直接调用,还可以将其包装在std::function对象内,当作线程函数传递给std::thread对象,也可以传递给需要可调用对象的函数。

std::packaged_task作为函数对象而被调用,它就会通过函数调用操作符接收参数,并将其进一步传递给包装在内的任务函数,由其异步运行得出结果,并将结果保存到std::future对象内部,再通过get_future()获取此对象。因此,为了在未来的适当时刻执行某项任务,我们可以将其包装在std::packaged_task对象内,取得对应的future之后,才把该对象传递给其他线程,由它触发任务执行。

等到需要使用结果时,我们静候future准备就绪即可。

举一个不是很恰当的例子:

#pragma once
#include <deque>
#include <future>
#include <mutex>
#include <thread>
#include <utility>
#include <iostream>using namespace std;/** 模拟多线程加载 GUI 界面*/
std::mutex mt;
std::deque<std::packaged_task<std::string()>> tasks;
std::vector<future<std::string>> futures;void gui_thread()
{for (int i = 0; i < 3; ++i){std::packaged_task<std::string()> task;{std::unique_lock<std::mutex> lk(mt);if (tasks.empty())continue;task = std::move(tasks.front());tasks.pop_front();}task();}}template <typename Func>
std::future<std::string> post_task_for_gui(Func f)
{std::packaged_task<std::string()> task(f);std::future<std::string> res = task.get_future();std::lock_guard<std::mutex> lk(mt);tasks.push_back(std::move(task));return res;
}void start_422()
{for (int i = 0; i < 3; ++i){futures.push_back(post_task_for_gui([=]()-> std::string{std::this_thread::sleep_for(3s);return std::format("第 {} 任务执行完毕", i);}));}cout << "任务提交完成" << endl;std::thread gui_background_thread(gui_thread);if (gui_background_thread.joinable())gui_background_thread.detach(); //后台执行for (auto& value : futures){cout << value.get() << endl;}
}

本例采用std::packaged_task<void()>表示任务,包装某个函数(或可调用对象),它不接收参数,返回void(倘若真正的任务函数返回任何其他类型的值,则会被丢弃)。

这里,我们采用最简单的任务举例,但前文已提过,std::packaged_task也能用于更复杂的情况。针对不同的任务函数,std::packaged_task的函数调用操作符须就此修改参数,保存于相关的future实例内的返回值类型也须变动,而我们只要通过模板参数,指定对应任务的函数签名即可。

我们可轻松扩展上例,改动那些只准许在GUI线程上运行的任务,令其接收参数,并凭借std::future返回结果,std::future不再局限于充当指标,示意任务是否完成。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/407990.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

js分页--存储数据并进行分页

//分页方法var page function(){this.v {o:null,//ul父级层home:null,previous:null,next:null,last:null, list:[],pageSize:10,pageIndex:0,pageCount:0,rowCount:0};this.init function(){var _this this;_this.v.o.find("li").each(function(i,o){_this.v.…

c/c++面试试题(一)

1.求下面函数的返回值&#xff08;微软&#xff09;int func(x) { int countx 0; while(x) { countx ; x x&(x-1); } return countx; } 假定x 9999。 答案&#xff1a;8思路&#xff1a;将x转化为2进制&#xff0c;看含有的1…

react(78)--vs打开setting.json

1.ctrl shift p 2.输入setting 3.找到这一项

stdspan ---C++20

std::span —C20 std::span的定义 template<class T,std::size_t Extent std::dynamic_extent > class span;std::span是指向一组连续的对象的对象, 是一个视图view, 不是一个拥有者owner 一组连续的对象可以是 C 数组, 带着大小的指针, std::array, 或者 std::strin…

2. Get the codes from GIT

Clone the code from git. Click the “GitEx Clone”. Paste the url into the “Repository to clone”. You can get the route from git repository from it: https://msstash.companydomainname.com/ .Find the project which you want to download and then click the “…

按钮控件数组

Public Class ButtonArray Inherits System.Collections.CollectionBase Private ReadOnly HostForm As System.Windows.Forms.Form 创建类的构造函数。 Visual Basic Public Sub New(ByVal host As System.Windows.Forms.Form) HostForm host Me.Add…

c/c++面试试题(二)

21. New delete 与malloc free 的联系与区别?答案&#xff1a;都是在堆(heap)上进行动态的内存操作。用malloc函数需要指定内存分配的字节数并且不能初始化对象&#xff0c;new 会自动调用对象的构造函数。delete 会调用对象的destructor&#xff0c;而free 不会调用对象的des…

The Ranges Library (2) --- C++20

The Ranges Library (2) — C20 比较std与std::ranges算法 比较一下std::sort和std::ranges::sort std::sort template< class RandomIt > constexpr void sort( RandomIt first, RandomIt last );template< class ExecutionPolicy, class RandomIt > void sor…

react(79)--ant design确认框

<Popconfirmplacement"rightBottom"title{text}onConfirm{confirm}okText"Yes"cancelText"No"><Button>RB</Button></Popconfirm>

程序中的得与失

俗话说&#xff0c;舍得&#xff0c;有舍便有得&#xff0c;程序或许和世间万物一个样&#xff0c;讲究阴阳平衡。或许您写程序过程中&#xff0c;得到一颗歪脖树&#xff0c;却放弃了一大片大森林&#xff0c;能正确的取舍矛盾体双方的关系&#xff0c;或许是您扎实功底的体现…

[转]新东方老师上课讲的笑话(太有才了)

[张洪伟] 起名字的问题&#xff1a;中西方都不愿意以鲜花、野草起名字&#xff0c;什么牡丹玫瑰&#xff0c;小红小翠了&#xff0c;一听就变味了&#xff1b;张建、李建&#xff0c;但不能叫范建&#xff08;贱&#xff09;了&#xff1b;北京以前有个建&#xff08;贱&#x…

c/c++面试试题(三)

慧通&#xff1a; 什么是预编译何时需要预编译&#xff1a;&#xff11;、总是使用不经常改动的大型代码体。 &#xff12;、程序由多个模块组成&#xff0c;所有模块都使用一组标准的包含文件和相同的编译选项。在这种情况下&#xff0c;可以将所有包含文件预编译为一个预编译…

mysql安装使用--2 用户管理

1 修改mysql.user表 添加用户 mysql> INSERT INTO mysql.user (Host,User,Password) VALUES (\%\,\system\, PASSWORD(\manager\)); mysql> FLUSH PRIVILEGES 2 create 和 grant命令省略 3 user表内容 MySQL用户名由两部分组成&#xff1a;(user, host)&#xff0c;二者…

constexpr if --- C++ 20

constexpr if — C 20 constexpr if 可以让我们实现条件编译 template <typename T> auto getResult(T t) {if constexpr (std::is_integral_v<T>)return *t;elsereturn t; }如果T是intergral类型,执行第一个分支,否则执行第二个分支 还记得前文写过的模板元编程…

WPF中的动画

WPF中的动画 周银辉动画无疑是WPF中最吸引人的特色之一&#xff0c;其可以像Flash一样平滑地播放并与程序逻辑进行很好的交互。这里我们讨论一下故事板。在WPF中我们采用Storyboard&#xf…

c/c++面试试题(四)

華為1、局部变量能否和全局变量重名&#xff1f;答&#xff1a;能&#xff0c;局部会屏蔽全局。要用全局变量&#xff0c;需要使用"::"局部变量可以与全局变量同名&#xff0c;在函数内引用这个变量时&#xff0c;会用到同名的局部变量&#xff0c;而不会用到全局变量…

[访问系统] Api_Win32_Mac类工具包 (转载)

点击下载 Api_Win32_Mac.zip using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Runtime.InteropServices;namespace BaseFunction {class API{[DllImport("kernel32")]//内存public static extern void GlobalM…

constexpr 函数

constexpr 函数 — C 20 constexpr double pi 3.14;constexpr允许你在编译时使用典型的C函数语法进行编程,但这并不意味之constexpr只和编译期有关 constexpr函数可以在编译期运行,也可以在运行时运行 但在以下情况constexpr函数必须在编译期运行: constexpr函数在编译的上…