You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

80 lines
1.9 KiB
C++

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

#include <functional>
#include <mutex>
#include <condition_variable>
#include <atomic>
#include <future>
#include <queue>
/**
* 异步任务执行类,它的主要作用是让任务都在一个后台线程中排队执行,避免业务代码中到处加锁
*/
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;
/*
* 根据 cppreference 的说法std::condition_variable 只能 std::unique_lock 的情况下生效,
* 这里采用 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;
};