mirror of
https://github.com/thinkonmay/sunshine-sdk.git
synced 2026-08-06 16:30:49 +00:00
remove task and thread pool
This commit is contained in:
parent
6781fd8da3
commit
c51fdc1a02
@ -67,8 +67,6 @@ set(SUNSHINE_TARGET_FILES
|
||||
"${CMAKE_SOURCE_DIR}/src/audio.h"
|
||||
"${CMAKE_SOURCE_DIR}/src/platform/common.h"
|
||||
"${CMAKE_SOURCE_DIR}/src/move_by_copy.h"
|
||||
"${CMAKE_SOURCE_DIR}/src/task_pool.h"
|
||||
"${CMAKE_SOURCE_DIR}/src/thread_pool.h"
|
||||
"${CMAKE_SOURCE_DIR}/src/thread_safe.h"
|
||||
"${CMAKE_SOURCE_DIR}/src/sync.h"
|
||||
"${CMAKE_SOURCE_DIR}/src/round_robin.h"
|
||||
|
||||
@ -4,7 +4,6 @@
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "thread_pool.h"
|
||||
#include "thread_safe.h"
|
||||
|
||||
extern bool display_cursor;
|
||||
|
||||
@ -159,13 +159,6 @@ main(int argc, char *argv[]) {
|
||||
// Wait as long as possible to terminate Sunshine.exe during logoff/shutdown
|
||||
SetProcessShutdownParameters(0x100, SHUTDOWN_NORETRY);
|
||||
|
||||
// We must create a hidden window to receive shutdown notifications since we load gdi32.dll
|
||||
std::promise<HWND> session_monitor_hwnd_promise;
|
||||
auto session_monitor_hwnd_future = session_monitor_hwnd_promise.get_future();
|
||||
std::promise<void> session_monitor_join_thread_promise;
|
||||
auto session_monitor_join_thread_future = session_monitor_join_thread_promise.get_future();
|
||||
|
||||
|
||||
auto platf_deinit_guard = platf::init();
|
||||
|
||||
|
||||
|
||||
262
src/task_pool.h
262
src/task_pool.h
@ -1,262 +0,0 @@
|
||||
/**
|
||||
* @file src/task_pool.h
|
||||
* @brief todo
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <chrono>
|
||||
#include <deque>
|
||||
#include <functional>
|
||||
#include <future>
|
||||
#include <mutex>
|
||||
#include <optional>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include "move_by_copy.h"
|
||||
#include "utility.h"
|
||||
namespace task_pool_util {
|
||||
|
||||
class _ImplBase {
|
||||
public:
|
||||
// _unique_base_type _this_ptr;
|
||||
|
||||
inline virtual ~_ImplBase() = default;
|
||||
|
||||
virtual void
|
||||
run() = 0;
|
||||
};
|
||||
|
||||
template <class Function>
|
||||
class _Impl: public _ImplBase {
|
||||
Function _func;
|
||||
|
||||
public:
|
||||
_Impl(Function &&f):
|
||||
_func(std::forward<Function>(f)) {}
|
||||
|
||||
void
|
||||
run() override {
|
||||
_func();
|
||||
}
|
||||
};
|
||||
|
||||
class TaskPool {
|
||||
public:
|
||||
typedef std::unique_ptr<_ImplBase> __task;
|
||||
typedef _ImplBase *task_id_t;
|
||||
|
||||
typedef std::chrono::steady_clock::time_point __time_point;
|
||||
|
||||
template <class R>
|
||||
class timer_task_t {
|
||||
public:
|
||||
task_id_t task_id;
|
||||
std::future<R> future;
|
||||
|
||||
timer_task_t(task_id_t task_id, std::future<R> &future):
|
||||
task_id { task_id }, future { std::move(future) } {}
|
||||
};
|
||||
|
||||
protected:
|
||||
std::deque<__task> _tasks;
|
||||
std::vector<std::pair<__time_point, __task>> _timer_tasks;
|
||||
std::mutex _task_mutex;
|
||||
|
||||
public:
|
||||
TaskPool() = default;
|
||||
TaskPool(TaskPool &&other) noexcept:
|
||||
_tasks { std::move(other._tasks) }, _timer_tasks { std::move(other._timer_tasks) } {}
|
||||
|
||||
TaskPool &
|
||||
operator=(TaskPool &&other) noexcept {
|
||||
std::swap(_tasks, other._tasks);
|
||||
std::swap(_timer_tasks, other._timer_tasks);
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <class Function, class... Args>
|
||||
auto
|
||||
push(Function &&newTask, Args &&...args) {
|
||||
static_assert(std::is_invocable_v<Function, Args &&...>, "arguments don't match the function");
|
||||
|
||||
using __return = std::invoke_result_t<Function, Args &&...>;
|
||||
using task_t = std::packaged_task<__return()>;
|
||||
|
||||
auto bind = [task = std::forward<Function>(newTask), tuple_args = std::make_tuple(std::forward<Args>(args)...)]() mutable {
|
||||
return std::apply(task, std::move(tuple_args));
|
||||
};
|
||||
|
||||
task_t task(std::move(bind));
|
||||
|
||||
auto future = task.get_future();
|
||||
|
||||
std::lock_guard<std::mutex> lg(_task_mutex);
|
||||
_tasks.emplace_back(toRunnable(std::move(task)));
|
||||
|
||||
return future;
|
||||
}
|
||||
|
||||
void
|
||||
pushDelayed(std::pair<__time_point, __task> &&task) {
|
||||
std::lock_guard lg(_task_mutex);
|
||||
|
||||
auto it = _timer_tasks.cbegin();
|
||||
for (; it < _timer_tasks.cend(); ++it) {
|
||||
if (std::get<0>(*it) < task.first) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
_timer_tasks.emplace(it, task.first, std::move(task.second));
|
||||
}
|
||||
|
||||
/**
|
||||
* @return an id to potentially delay the task.
|
||||
*/
|
||||
template <class Function, class X, class Y, class... Args>
|
||||
auto
|
||||
pushDelayed(Function &&newTask, std::chrono::duration<X, Y> duration, Args &&...args) {
|
||||
static_assert(std::is_invocable_v<Function, Args &&...>, "arguments don't match the function");
|
||||
|
||||
using __return = std::invoke_result_t<Function, Args &&...>;
|
||||
using task_t = std::packaged_task<__return()>;
|
||||
|
||||
__time_point time_point;
|
||||
if constexpr (std::is_floating_point_v<X>) {
|
||||
time_point = std::chrono::steady_clock::now() + std::chrono::duration_cast<std::chrono::nanoseconds>(duration);
|
||||
}
|
||||
else {
|
||||
time_point = std::chrono::steady_clock::now() + duration;
|
||||
}
|
||||
|
||||
auto bind = [task = std::forward<Function>(newTask), tuple_args = std::make_tuple(std::forward<Args>(args)...)]() mutable {
|
||||
return std::apply(task, std::move(tuple_args));
|
||||
};
|
||||
|
||||
task_t task(std::move(bind));
|
||||
|
||||
auto future = task.get_future();
|
||||
auto runnable = toRunnable(std::move(task));
|
||||
|
||||
task_id_t task_id = &*runnable;
|
||||
|
||||
pushDelayed(std::pair { time_point, std::move(runnable) });
|
||||
|
||||
return timer_task_t<__return> { task_id, future };
|
||||
}
|
||||
|
||||
/**
|
||||
* @param task_id The id of the task to delay.
|
||||
* @param duration The delay before executing the task.
|
||||
*/
|
||||
template <class X, class Y>
|
||||
void
|
||||
delay(task_id_t task_id, std::chrono::duration<X, Y> duration) {
|
||||
std::lock_guard<std::mutex> lg(_task_mutex);
|
||||
|
||||
auto it = _timer_tasks.begin();
|
||||
for (; it < _timer_tasks.cend(); ++it) {
|
||||
const __task &task = std::get<1>(*it);
|
||||
|
||||
if (&*task == task_id) {
|
||||
std::get<0>(*it) = std::chrono::steady_clock::now() + duration;
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (it == _timer_tasks.cend()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// smaller time goes to the back
|
||||
auto prev = it - 1;
|
||||
while (it > _timer_tasks.cbegin()) {
|
||||
if (std::get<0>(*it) > std::get<0>(*prev)) {
|
||||
std::swap(*it, *prev);
|
||||
}
|
||||
|
||||
--prev;
|
||||
--it;
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
cancel(task_id_t task_id) {
|
||||
std::lock_guard lg(_task_mutex);
|
||||
|
||||
auto it = _timer_tasks.begin();
|
||||
for (; it < _timer_tasks.cend(); ++it) {
|
||||
const __task &task = std::get<1>(*it);
|
||||
|
||||
if (&*task == task_id) {
|
||||
_timer_tasks.erase(it);
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
std::optional<std::pair<__time_point, __task>>
|
||||
pop(task_id_t task_id) {
|
||||
std::lock_guard lg(_task_mutex);
|
||||
|
||||
auto pos = std::find_if(std::begin(_timer_tasks), std::end(_timer_tasks), [&task_id](const auto &t) { return t.second.get() == task_id; });
|
||||
|
||||
if (pos == std::end(_timer_tasks)) {
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
return std::move(*pos);
|
||||
}
|
||||
|
||||
std::optional<__task>
|
||||
pop() {
|
||||
std::lock_guard lg(_task_mutex);
|
||||
|
||||
if (!_tasks.empty()) {
|
||||
__task task = std::move(_tasks.front());
|
||||
_tasks.pop_front();
|
||||
return task;
|
||||
}
|
||||
|
||||
if (!_timer_tasks.empty() && std::get<0>(_timer_tasks.back()) <= std::chrono::steady_clock::now()) {
|
||||
__task task = std::move(std::get<1>(_timer_tasks.back()));
|
||||
_timer_tasks.pop_back();
|
||||
return task;
|
||||
}
|
||||
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
bool
|
||||
ready() {
|
||||
std::lock_guard<std::mutex> lg(_task_mutex);
|
||||
|
||||
return !_tasks.empty() || (!_timer_tasks.empty() && std::get<0>(_timer_tasks.back()) <= std::chrono::steady_clock::now());
|
||||
}
|
||||
|
||||
std::optional<__time_point>
|
||||
next() {
|
||||
std::lock_guard<std::mutex> lg(_task_mutex);
|
||||
|
||||
if (_timer_tasks.empty()) {
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
return std::get<0>(_timer_tasks.back());
|
||||
}
|
||||
|
||||
private:
|
||||
template <class Function>
|
||||
std::unique_ptr<_ImplBase>
|
||||
toRunnable(Function &&f) {
|
||||
return std::make_unique<_Impl<Function>>(std::forward<Function &&>(f));
|
||||
}
|
||||
};
|
||||
} // namespace task_pool_util
|
||||
@ -1,131 +0,0 @@
|
||||
/**
|
||||
* @file src/thread_pool.h
|
||||
* @brief todo
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "task_pool.h"
|
||||
#include <thread>
|
||||
|
||||
namespace thread_pool_util {
|
||||
/**
|
||||
* Allow threads to execute unhindered while keeping full control over the threads.
|
||||
*/
|
||||
class ThreadPool: public task_pool_util::TaskPool {
|
||||
public:
|
||||
typedef TaskPool::__task __task;
|
||||
|
||||
private:
|
||||
std::vector<std::thread> _thread;
|
||||
|
||||
std::condition_variable _cv;
|
||||
std::mutex _lock;
|
||||
|
||||
bool _continue;
|
||||
|
||||
public:
|
||||
ThreadPool():
|
||||
_continue { false } {}
|
||||
|
||||
explicit ThreadPool(int threads):
|
||||
_thread(threads), _continue { true } {
|
||||
for (auto &t : _thread) {
|
||||
t = std::thread(&ThreadPool::_main, this);
|
||||
}
|
||||
}
|
||||
|
||||
~ThreadPool() noexcept {
|
||||
if (!_continue) return;
|
||||
|
||||
stop();
|
||||
join();
|
||||
}
|
||||
|
||||
template <class Function, class... Args>
|
||||
auto
|
||||
push(Function &&newTask, Args &&...args) {
|
||||
std::lock_guard lg(_lock);
|
||||
auto future = TaskPool::push(std::forward<Function>(newTask), std::forward<Args>(args)...);
|
||||
|
||||
_cv.notify_one();
|
||||
return future;
|
||||
}
|
||||
|
||||
void
|
||||
pushDelayed(std::pair<__time_point, __task> &&task) {
|
||||
std::lock_guard lg(_lock);
|
||||
|
||||
TaskPool::pushDelayed(std::move(task));
|
||||
}
|
||||
|
||||
template <class Function, class X, class Y, class... Args>
|
||||
auto
|
||||
pushDelayed(Function &&newTask, std::chrono::duration<X, Y> duration, Args &&...args) {
|
||||
std::lock_guard lg(_lock);
|
||||
auto future = TaskPool::pushDelayed(std::forward<Function>(newTask), duration, std::forward<Args>(args)...);
|
||||
|
||||
// Update all timers for wait_until
|
||||
_cv.notify_all();
|
||||
return future;
|
||||
}
|
||||
|
||||
void
|
||||
start(int threads) {
|
||||
_continue = true;
|
||||
|
||||
_thread.resize(threads);
|
||||
|
||||
for (auto &t : _thread) {
|
||||
t = std::thread(&ThreadPool::_main, this);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
stop() {
|
||||
std::lock_guard lg(_lock);
|
||||
|
||||
_continue = false;
|
||||
_cv.notify_all();
|
||||
}
|
||||
|
||||
void
|
||||
join() {
|
||||
for (auto &t : _thread) {
|
||||
t.join();
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
void
|
||||
_main() {
|
||||
while (_continue) {
|
||||
if (auto task = this->pop()) {
|
||||
(*task)->run();
|
||||
}
|
||||
else {
|
||||
std::unique_lock uniq_lock(_lock);
|
||||
|
||||
if (ready()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!_continue) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (auto tp = next()) {
|
||||
_cv.wait_until(uniq_lock, *tp);
|
||||
}
|
||||
else {
|
||||
_cv.wait(uniq_lock);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Execute remaining tasks
|
||||
while (auto task = this->pop()) {
|
||||
(*task)->run();
|
||||
}
|
||||
}
|
||||
};
|
||||
} // namespace thread_pool_util
|
||||
Loading…
Reference in New Issue
Block a user