class std::packaged_task被用来同时存储callable object,以及该callable object的返回值(也可能是个异常).
#include <iostream>
#include <thread>
#include <future>
#include <exception>
int main()
{
std::packaged_task<int(const int&)> t1; //空的packaged_task即没有shared state,也没有callable object.
std::packaged_task<int(const int&)> t2([](const int& number) { return 10; }); //构造函数,运行时候构建一个shared state,并且存储一个callable object进去.
t1 = std::move(t2); //移动赋值运算符.这样一来t2中的shared state和callable object都转移到了t1中,t2不可再使用.
std::future<int> result = t1.get_future();
std::thread t3(std::move(t1), 20); //此时t1处于无效状态.
t3.detach(); //t3成为一个独立的线程.
int value = result.get(); //如果t3内的callable object还没有执行完成,那么会阻塞调用result.get()的线程直到t3类的callable object调用完成.
std::cout << "result: " << value << std::endl;
return 0;
}
----------------------------我是分割线------------------------------
std::packaged_task构造函数:
packaged_task() noexcept;
template <class Fn>
explicit packaged_task (Fn&& fn);
template <class Fn, class Alloc>
explicit packaged_task (allocator_arg_t aa, const Alloc& alloc, Fn&& fn);
packaged_task (const packaged_task&) = delete; //不支持拷贝.
packaged_task (packaged_task&& x) noexcept;
1,默认构造函数构建一个std::packaged_task对象,即没有shared state,也没有callable object.
2,显式构造函数接受一个callable object初始化std::packaged_task。同时创建一个not ready的shared state.
3,被删除了的copy-constructor.
4,移动构造函数,被移动的对象不再可用,且当前对象获得被移动对象的callable object和shared state.
std::packaged_task::get_future
该函数返回一个std::future对象且该std::future与当前std::packaged_task共同使用同一个shared state.这样也就意味着,如果我们对被返回出来的std::future调用get(),wait()等,如果std::packaged_task中的callable object未执行完成(也就是shared state还处于not ready状态),这样就会阻塞当前正在调用get()或者wait()的线程.
future<Ret> get_future();
#include <iostream>
#include <thread>
#include <future>
#include <string>
int function(const int& number)
{
return number * 3;
}
int main()
{
std::packaged_task<int(const int&)> t1(function);
std::future<int> result = t1.get_future(); //此时result 和 t1共享shared state.
std::thread t2(std::move(t1), 20); //t1被移动变成不可用状态.
t2.detach();
int value = result.get(); //这里调用get(),如果t2未执行完成(也就是shared state处于not ready状态),会block当前调用get()的线程(这里是main线程).
std::cout << "value: " << value << std::endl;
return 0;
}
std::packaged_task::make_ready_at_thread_exit
调用当前std::packaged_task中的callable object以一个独立的线程运行该callable object,并转发参数进去callable object,但是callable object调用完成后并不是立即把该std::packaged_task中的shared state设置为ready,而是直到该线程完全结束的时候才设为ready.
void make_ready_at_thread_exit (args... args);
std::packaged_task::operator=
该std::packaged_task对象的拷贝赋值运算被删除了,也就是说std::packaged_task对象不能被拷贝.
但是可以被移动,被移动的std::packaged_task的shared state和callable object被移动当前std::packaged_task.被移动对象变成不可用的状态.
packaged_task& operator= (packaged_task&& rhs) noexcept;
packaged_task& operator= (const packaged_task&) = delete;//拷贝构造函数被删除了.
std::packaged_task::operator()
调用当前对象内的callable object,并转发参数进去(不过需要注意的是如果我们通过operator()调用callable object并不是并行的):
1,如果当前std::packaged_task中的callable object执行完成,则callable object的返回值被存储到当前std::packaged_task的shared state中,且将该shared state的状态设置为ready.
2,如果当前的std::packaged_task中的callable object在执行过程中抛出了异常,那么该异常会被捕获,也被存储在shared state中,并且该shared state被设置为ready.
#include <iostream>
#include <thread>
#include <future>
#include <string>
#include <utility>
class Object {
private:
int number;
public:
Object();
~Object() = default;
int& operator()(const int& number)noexcept;
};
Object::Object()
:number(1)
{
//
}
int& Object::operator()(const int& number)noexcept
{
this->number = 20 * number;
std::this_thread::sleep_for(std::chrono::seconds(2));
return (this->number);
}
class MyObject {
private:
int number;
public:
inline MyObject():number(1){}
~MyObject() = default;
int getNumber(const int& num)noexcept
{
return (this->number * num);
}
};
int function(const int& number)
{
return number * 3;
}
int main()
{
//callable object case 1:
std::packaged_task<int(const int&)> t1(function);
std::future<int> result = t1.get_future(); //此时result 和 t1共享shared state.
std::thread t2(std::move(t1), 20); //t1被移动变成不可用状态.
t2.detach();
int value = result.get(); //这里调用get(),如果t2未执行完成(也就是shared state处于not ready状态),会block当前调用get()的线程(这里是main线程).
std::cout << "value: " << value << std::endl;
//callable object case 2:
try {
Object object;
std::packaged_task<int& (const int&)noexcept> t3(object);
std::future<int&> result1 = t3.get_future();
//t3(20); //调用callable object但是并不会并行调用.
std::thread t4(std::move(t3), 20);
t4.detach();
std::cout << " test " << std::endl;
int value1 = result1.get();
std::cout << "value1: " << value1 << std::endl;
}catch (const std::exception& e) {
std::cerr << "exception!" << std::endl;
}
//callable object case 3:
MyObject myObject;
std::function<int(const int&)> memberFunction = std::bind(&MyObject::getNumber, &myObject, std::placeholders::_1);
std::packaged_task<int(const int&)> t5(memberFunction);
std::future<int> result2 = t5.get_future();
std::thread t6(std::move(t5), 20);
t6.detach();
int value2 = result2.get();
std::cout << "value2: " << value2 << std::endl;
return 0;
}
std::packaged_task::reset
当我们执行完了callable object(无论是通过当前std::packaged_task的operator(),还是通过std::thread),当前std::packaged_task对象内的shared state都被设置为了ready,这样也就造成了我们通过调用当前std::packaged_task对象的get_future()函数获得的std::future只能get()一次,
那么我们想要再次执行该callable object怎么办呢?这个时候就需要调用当前std::packaged_task对象的reset()函数了给当前std::packaged_task对象创建一个新的shared state且处于not ready状态.
void reset();
#include <iostream>
#include <thread>
#include <future>
#include <string>
int getNumber(const int& number)
{
return number * 20;
}
int main()
{
std::packaged_task<int(const int&)> package(getNumber);
std::future<int> result = package.get_future();
package(20);
int value = result.get();
std::cout << "value(now shared state is ready): " << value << std::endl;
std::cout << "reset the shared state." << std::endl;
package.reset();
std::future<int> result2 = package.get_future();
std::thread t2(std::move(package), 40); //注意这里用了std::move(),package对象会不再可用.
t2.detach();
int value2 = result2.get();
std::cout << " value2(now share state is again ready): " << value2 << std::endl;
return 0;
}