|
|
|
|
|
#include <functional>
|
|
|
|
|
|
#include <mutex>
|
|
|
|
|
|
#include <condition_variable>
|
|
|
|
|
|
#include <atomic>
|
|
|
|
|
|
#include <future>
|
|
|
|
|
|
#include <queue>
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* <EFBFBD>첽<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ִ<EFBFBD><EFBFBD><EFBFBD>࣬<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ҫ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>һ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>̨<EFBFBD>߳<EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ŷ<EFBFBD>ִ<EFBFBD>У<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ҵ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>е<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
|
|
|
|
|
*/
|
|
|
|
|
|
class AsyncWorker
|
|
|
|
|
|
{
|
|
|
|
|
|
public:
|
|
|
|
|
|
AsyncWorker()
|
|
|
|
|
|
: done(false)
|
|
|
|
|
|
{
|
|
|
|
|
|
worker_thread = std::thread(&AsyncWorker::workerLoop, this);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
~AsyncWorker()
|
|
|
|
|
|
{
|
|
|
|
|
|
{
|
|
|
|
|
|
std::lock_guard<std::mutex> lock(queue_mutex);
|
|
|
|
|
|
done = true;
|
|
|
|
|
|
}
|
|
|
|
|
|
cond_var.notify_all();
|
|
|
|
|
|
if (worker_thread.joinable())
|
|
|
|
|
|
{
|
|
|
|
|
|
worker_thread.join();
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
template <typename Func>
|
|
|
|
|
|
auto postTask(Func task) -> std::future<decltype(task())>
|
|
|
|
|
|
{
|
|
|
|
|
|
using result_type = decltype(task());
|
|
|
|
|
|
auto packaged_task = std::make_shared<std::packaged_task<result_type()>>(task);
|
|
|
|
|
|
std::future<result_type> result = packaged_task->get_future();
|
|
|
|
|
|
{
|
|
|
|
|
|
std::lock_guard<std::mutex> lock(queue_mutex);
|
|
|
|
|
|
task_queue.push([packaged_task] { (*packaged_task)(); });
|
|
|
|
|
|
}
|
|
|
|
|
|
cond_var.notify_one();
|
|
|
|
|
|
return result;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
|
void workerLoop()
|
|
|
|
|
|
{
|
|
|
|
|
|
while (true)
|
|
|
|
|
|
{
|
|
|
|
|
|
std::function<void()> task;
|
|
|
|
|
|
{
|
|
|
|
|
|
std::unique_lock<std::mutex> lock(queue_mutex);
|
|
|
|
|
|
cond_var.wait(lock, [this] { return !task_queue.empty() || done; });
|
|
|
|
|
|
if (done && task_queue.empty())
|
|
|
|
|
|
{
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
task = std::move(task_queue.front());
|
|
|
|
|
|
task_queue.pop();
|
|
|
|
|
|
}
|
|
|
|
|
|
task();
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
std::thread worker_thread;
|
|
|
|
|
|
std::queue<std::function<void()>> task_queue;
|
|
|
|
|
|
std::mutex queue_mutex;
|
|
|
|
|
|
/*
|
|
|
|
|
|
* <EFBFBD><EFBFBD><EFBFBD><EFBFBD> cppreference <EFBFBD><EFBFBD>˵<EFBFBD><EFBFBD><EFBFBD><EFBFBD>std::condition_variable ֻ<EFBFBD><EFBFBD> std::unique_lock <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ч<EFBFBD><EFBFBD>
|
|
|
|
|
|
* <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> std::condition_variable_any
|
|
|
|
|
|
* The condition_variable_any class is a generalization of std::condition_variable.
|
|
|
|
|
|
* Whereas std::condition_variable works only on std::unique_lock<std::mutex>,
|
|
|
|
|
|
* condition_variable_any can operate on any lock that meets the BasicLockable requirements.
|
|
|
|
|
|
*/
|
|
|
|
|
|
std::condition_variable_any cond_var;
|
|
|
|
|
|
std::atomic<bool> done;
|
|
|
|
|
|
};
|