C++11中的std::packaged_task如何用

C++11中的std::packaged_task如何用

这篇文章主要介绍了C++11中的std::packaged_task如何用的相关知识,内容详细易懂,操作简单快捷,具有一定借鉴价值,相信大家阅读完这篇C++11中的std::packaged_task如何用文章都会有所收获,下面我们一起来看看吧。

C++11中的std::packaged_task是个模板类。

C++11中的std::packaged_task如何用

std::packaged_task包装任何可调用目标(函数、lambda表达式、bind表达式、函数对象)以便它可以被异步调用。它的返回值或抛出的异常被存储于能通过std::future对象访问的共享状态中。

std::packaged_task类似于std::function,但是会自动将其结果传递给std::future对象。

std::packaged_task对象内部包含两个元素:

(1).存储的任务(stored task)是一些可调用的对象(例如函数指针、成员或函数对象的指针)( A stored task, which is some callable object (such as a function pointer, pointer to member or function object))。

(2).共享状态,它可以存储调用存储的任务(stored task)的结果,并可以通过std::future进行异步访问(A shared state, which is able to store the results of calling the stored task and be accessed asynchronously through a future)。

通过调用std::packaged_task的get_future成员将共享状态与std::future对象关联。调用之后,两个对象共享相同的共享状态:(1).std::packaged_task对象是异步提供程序(asynchronous provider),应通过调用存储的任务(stored task)在某个时刻将共享状态设置为就绪。

(2).std::future对象是一个异步返回对象,可以检索共享状态的值,并在必要时等待其准备就绪。

共享状态的生存期至少要持续到与之关联的最后一个对象释放或销毁为止。

std::packaged_task不会自己启动,你必须调用它(A packaged_task won't start on it's own, you have to invoke it)。

模板类std::packaged_task成员函数包括:

1.构造函数:

(1).默认构造函数:无共享状态无存储任务(no shared state and no stored task)情况下初始化对象。

(2). initialization constructor:该对象具有共享状态,且其存储的任务由fn初始化。

(3). initialization constructor with allocator。

(4).禁用拷贝构造。

(5).支持移动构造。

2. 析构函数:

(1).放弃(abandon)共享状态并销毁packaged_task对象。

(2). 如果有其它future对象关联到同一共享状态,则共享状态本身不会被销毁。

(3). 如果packaged_task对象在共享状态准备就绪前被销毁,则共享状态自动准备就绪并包含一个std::future_error类型的异常。

3. get_future函数:

(1).返回一个与packaged_task对象的共享状态关联的std::future对象。

(2).一旦存储的任务被调用,返回的std::future对象就可以访问packaged_task对象在共享状态上设置的值或异常。

(3).每个packaged_task共享状态只能被一个std::future对象检索(Only one future object can be retrieved for each packaged_task shared state)。

(4).调用此函数后,packaged_task应在某个时候使其共享状态准备就绪(通过调用其存储的任务),否则将在销毁后自动准备就绪并包含一个std::future_error类型的异常。

4. make_ready_at_thread_exit函数:在线程退出时才使共享状态ready而不是在调用完成后就立即ready。

5. operator=:

(1).禁用拷贝赋值。

(2).支持移动赋值。

6. operator():

(1).call stored task。

(2).如果对存储任务的调用成功完成或抛出异常,则返回的值或捕获的异常存储在共享状态,共享状态准备就绪(解除阻塞当前等待它的所有线程)。

7. reset函数:

(1).在保持相同存储的任务的同时,以新的共享状态重置对象。

(2).允许再次调用存储的任务。

(3).与对象关联的之前的共享状态被放弃(就像packaged_task被销毁了一样)。

(4).在内部,该函数的行为就像是移动赋值了一个新构造的packaged_task一样(Internally, the function behaves as if move-assigned a newly constructed packaged_task (with its stored task as argument))。

8. swap函数/非成员模板函数swap:交换共享状态和存储的任务(stored task)。

9. valid函数:检查packaged_task对象是否具有共享状态。

详细用法见下面的测试代码,下面是从其他文章中copy的测试代码,部分作了调整,详细内容介绍可以参考对应的reference:

#include"future.hpp"#include<iostream>#include<future>#include<chrono>#include<utility>#include<thread>#include<functional>#include<memory>#include<exception>#include<numeric>#include<vector>#include<cmath>#include<string>namespacefuture_{/////////////////////////////////////////////////////////////reference:http://www.cplusplus.com/reference/future/packaged_task/inttest_packaged_task_1(){{//constructor/get_future/operator=/validstd::packaged_task<int(int)>foo;//default-constructedstd::packaged_task<int(int)>bar([](intx){returnx*2;});//initializedfoo=std::move(bar);//move-assignmentstd::cout<<"valid:"<<foo.valid()<<"\n";std::future<int>ret=foo.get_future();//getfuturestd::thread(std::move(foo),10).detach();//spawnthreadandcalltaskintvalue=ret.get();//waitforthetasktofinishandgetresultstd::cout<<"Thedoubleof10is"<<value<<".\n";}{//reset/operator()std::packaged_task<int(int)>tsk([](intx){returnx*3;});//packagetaskstd::future<int>fut=tsk.get_future();tsk(33);std::cout<<"Thetripleof33is"<<fut.get()<<".\n";//re-usesametaskobject:tsk.reset();fut=tsk.get_future();std::thread(std::move(tsk),99).detach();std::cout<<"Thretripleof99is"<<fut.get()<<".\n";}{//constructor/get_futureautocountdown=[](intfrom,intto){for(inti=from;i!=to;--i){std::cout<<i<<'\n';std::this_thread::sleep_for(std::chrono::seconds(1));}std::cout<<"Liftoff!\n";returnfrom-to;};std::packaged_task<int(int,int)>tsk(countdown);//setuppackaged_taskstd::future<int>ret=tsk.get_future();//getfuturestd::threadth(std::move(tsk),5,0);//spawnthreadtocountdownfrom5to0intvalue=ret.get();//waitforthetasktofinishandgetresultstd::cout<<"Thecountdownlastedfor"<<value<<"seconds.\n";th.join();}return0;}/////////////////////////////////////////////////////////////reference:https://en.cppreference.com/w/cpp/thread/packaged_taskinttest_packaged_task_2(){{//lambdastd::packaged_task<int(int,int)>task([](inta,intb){returnstd::pow(a,b);});std::future<int>result=task.get_future();task(2,9);std::cout<<"task_lambda:\t"<<result.get()<<'\n';}{//bindstd::packaged_task<int()>task(std::bind([](intx,inty){returnstd::pow(x,y);},2,11));std::future<int>result=task.get_future();task();std::cout<<"task_bind:\t"<<result.get()<<'\n';}{//threadstd::packaged_task<int(int,int)>task([](intx,inty){returnstd::pow(x,y);});std::future<int>result=task.get_future();std::threadtask_td(std::move(task),2,10);task_td.join();std::cout<<"task_thread:\t"<<result.get()<<'\n';}return0;}/////////////////////////////////////////////////////////////reference:https://thispointer.com/c11-multithreading-part-10-packaged_task-example-and-tutorial/structDBDataFetcher{std::stringoperator()(std::stringtoken){//Dosomestufftofetchthedatastd::stringdata="DataFrom"+token;returndata;}};inttest_packaged_task_3(){//Createapackaged_task<>thatencapsulatedaFunctionObjectstd::packaged_task<std::string(std::string)>task(std::move(DBDataFetcher()));//Fetchtheassociatedfuture<>frompackaged_task<>std::future<std::string>result=task.get_future();//Passthepackaged_tasktothreadtorunasynchronouslystd::threadth(std::move(task),"Arg");//Jointhethread.Itsblockingandreturnswhenthreadisfinished.th.join();//Fetchtheresultofpackaged_task<>i.e.valuereturnedbygetDataFromDB()std::stringdata=result.get();std::cout<<data<<std::endl;return0;}/////////////////////////////////////////////////////////////reference:https://stackoverflow.com/questions/18143661/what-is-the-difference-between-packaged-task-and-asyncinttest_packaged_task_4(){//sleepsforonesecondandreturns1autosleep=[](){std::this_thread::sleep_for(std::chrono::seconds(1));return1;};{//std::packaged_task//>>>>>Apackaged_taskwon'tstartonit'sown,youhavetoinvokeitstd::packaged_task<int()>task(sleep);autof=task.get_future();task();//invokethefunction//Youhavetowaituntiltaskreturns.Sincetaskcallssleep//youwillhavetowaitatleast1second.std::cout<<"Youcanseethisafter1second\n";//However,f.get()willbeavailable,sincetaskhasalreadyfinished.std::cout<<f.get()<<std::endl;}{//std::async//>>>>>Ontheotherhand,std::asyncwithlaunch::asyncwilltrytorunthetaskinadifferentthread:autof=std::async(std::launch::async,sleep);std::cout<<"Youcanseethisimmediately!\n";//However,thevalueofthefuturewillbeavailableaftersleephasfinished//sof.get()canblockupto1second.std::cout<<f.get()<<"Thiswillbeshownafterasecond!\n";}return0;}}//namespacefuture_

关于“C++11中的std::packaged_task如何用”这篇文章的内容就介绍到这里,感谢各位的阅读!相信大家对“C++11中的std::packaged_task如何用”知识都有一定的了解,大家如果还想学习更多知识,欢迎关注恰卡编程网行业资讯频道。

发布于 2022-04-15 22:33:57
收藏
分享
海报
0 条评论
24
上一篇:C++中算法与泛型算法怎么应用 下一篇:c/c++中struct定义、声明、对齐如何实现
目录

    0 条评论

    本站已关闭游客评论,请登录或者注册后再评论吧~

    忘记密码?

    图形验证码