网站建设技术入股协议,新注册的公司怎么做网站,丹东网站推广,移动宽带续费多少钱std::packaged_task() —C17 并发编程
std::packaged_task连结了future对象与函数#xff08;或可调用对象#xff09;。
std::packaged_task对象在执行任务时#xff0c;会调用关联的函数#xff08;或可调用对象#xff09;#xff0c;把返回值保存为…std::packaged_task() —C17 并发编程
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_taskdouble(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 iostreamusing namespace std;/** 模拟多线程加载 GUI 界面*/
std::mutex mt;
std::dequestd::packaged_taskstd::string() tasks;
std::vectorfuturestd::string futures;void gui_thread()
{for (int i 0; i 3; i){std::packaged_taskstd::string() task;{std::unique_lockstd::mutex lk(mt);if (tasks.empty())continue;task std::move(tasks.front());tasks.pop_front();}task();}}template typename Func
std::futurestd::string post_task_for_gui(Func f)
{std::packaged_taskstd::string() task(f);std::futurestd::string res task.get_future();std::lock_guardstd::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_taskvoid()表示任务包装某个函数或可调用对象它不接收参数返回void倘若真正的任务函数返回任何其他类型的值则会被丢弃。
这里我们采用最简单的任务举例但前文已提过std::packaged_task也能用于更复杂的情况。针对不同的任务函数std::packaged_task的函数调用操作符须就此修改参数保存于相关的future实例内的返回值类型也须变动而我们只要通过模板参数指定对应任务的函数签名即可。
我们可轻松扩展上例改动那些只准许在GUI线程上运行的任务令其接收参数并凭借std::future返回结果std::future不再局限于充当指标示意任务是否完成。