packaged_task
1. packaged_task
packaged_task类似于将一个函数任务打包,然后换到其他地方去执行。通常多线程编程就会使用的这种方式。比如简易的线程池中。
packaged_task中<>放的是函数参数类型,类似std::function中放的东西。
packaged_task的返回值是void,通常获取执行的结果是使用std::future去接受get_future,然后调用future中的get方法。
#include <future>
#include <iostream>
int FunctionOne(int x) {
std::cout << "sub thread id : " << std::this_thread::get_id() << std::endl;
return x;
}
int main() {
std::cout << "main thread id : " << std::this_thread::get_id() << std::endl;
std::packaged_task<int(int)> tsk(FunctionOne);
// do somthing
tsk(666);
std::future<int> res = tsk.get_future();
int x = res.get();
std::cout << x << std::endl;
}
2.
2.1
通常而言我们不能像创建thread一样,将packaged_task中函数参数传进去
但是我们可以使用std::bind将参数打包,打包参数后就需要将packaged_task<>尖括号中的参数省略,而且还是需要执行。

#include <future>
#include <iostream>
#include <functional>
int FunctionOne(int x) {
std::cout << "sub thread id : " << std::this_thread::get_id() << std::endl;
return x;
}
int main() {
std::cout << "main thread id : " << std::this_thread::get_id() << std::endl;
std::packaged_task<int()> tsk(std::bind(FunctionOne, 666));
tsk(); // 需要理解这个,打包任务,不代表任务执行,只有调用任务才代表任务执行了。
std::future<int> fu = tsk.get_future();
std::cout << fu.get() <<std::endl;
// do somthing
} // do somthing

如果不类似tsk()函数,程序将不会正常结束,而会发生阻塞。
2.2

和future和promise一样,package_task只使用移动语义。
思考
1. std::package_task和std::async的异同?
std::async用于创建异步任务,std::packaged_task则将一个可调用对象(包括函数、函数对象、lambda表达式、std::bind表达式、std::function对象)进行包装,以便该任务能被异步调用(即在其他线程中调用)。二者均可通过std::future对象返回执行结果。二者使用的一个主要差别是:std::packaged_task需要等待执行结果返回,而std::async不必。
对于上述的第一句话怎么解释呢,就是async创建后,就会默认执行,后面直接调用get方法就好了,而packaged_task你需要自己调用。
2. 这里为什么要使用std::packaged_task,而不是直接使用std::bind?
感觉上packaged_task和std::bind没啥区别,但是package_task可以和future结合,进行异步调度。比如在在线程池中将任务打包,进行异步调用。这里举个简单例子,这段代码只是抛砖引玉.
#include <atomic>
#include <future>
#include <iostream>
#include <functional>
#include <chrono>
#include <mutex>
#include <thread>
#include <queue>
#include <condition_variable>
template <typename T>
class SafeQueue {
public:
bool Empty() {
std::lock_guard<std::mutex> lk(mtx_);
return q_.empty();
}
void Push(T task) {
std::unique_lock<std::mutex> lk(mtx_);
q_.push(task);
cv_.notify_one();
}
T Wait(int tm) {
std::unique_lock<std::mutex> lk(mtx_);
cv_.wait_for(lk, std::chrono::microseconds(tm), [&]() { return !q_.empty();});
T t;
if(!q_.empty()) {
t = q_.front();
q_.pop();
}
return t;
}
private:
std::queue<T> q_;
std::mutex mtx_;
std::condition_variable cv_;
}; // class SafeQueue
template<class T>
class ThreadManager {
public:
ThreadManager() { running_.store(true);}
~ThreadManager() {
running_.store(false);
}
void Worker() {
while (running_) {
T* tsk = safe_q_.Wait(20);
(*tsk)();
}
}
void AddTask(T* tsk) {
safe_q_.Push(tsk);
}
private:
SafeQueue<T*> safe_q_;
std::atomic<bool> running_{false};
}; // class ThreadManager
int FunctionOne(int x) {
std::cout << x << std::endl;
return 2 * x;
}
int main() {
ThreadManager<std::packaged_task<int()>> tm;
std::thread thd = std::thread(&ThreadManager<std::packaged_task<int()>>::Worker, &tm);
std::packaged_task<int()> tsk(std::bind(FunctionOne, 666));
std::future<int> fu = tsk.get_future();
tm.AddTask(&tsk);
std::cout << fu.get() <<std::endl;
std::this_thread::sleep_for(std::chrono::seconds(5));
if(thd.joinable()) {
thd.join();
}
}
注意
因为这里packaged_task只支持移动语义,所以我在这写多线程时用的是指针。

浙公网安备 33010602011771号