#pragma once #include #include #include #include #include #include #include #include #include #include class Worker { public: class WorkItem { public: WorkItem() = default; virtual ~WorkItem() = default; NO_MOVE(WorkItem); NO_COPY(WorkItem); virtual void doWork() = 0; }; template class WorkItemT : public WorkItem { public: T get() { return future.get(); } protected: std::promise promise; std::future future {promise.get_future()}; friend Worker; }; template static auto addWork(Params &&... params) { return instance.addWorkImpl(std::forward(params)...); } template using WorkPtrT = std::shared_ptr>; private: template class WorkItemTImpl : public WorkItemT { public: WorkItemTImpl(Params &&... params) : params {std::forward(params)...} { } private: void doWork() override { try { if constexpr (std::is_void_v) { std::apply( [](auto &&... p) { return std::invoke(p...); }, params); WorkItemT::promise.set_value(); } else { WorkItemT::promise.set_value(std::apply( [](auto &&... p) { return std::invoke(p...); }, params)); } } catch (...) { WorkItemT::promise.set_exception(std::current_exception()); } } std::tuple params; }; Worker(); ~Worker(); NO_COPY(Worker); NO_MOVE(Worker); using WorkPtr = std::shared_ptr; template auto addWorkImpl(Params &&... params) { using T = decltype(std::invoke(std::forward(params)...)); auto work = std::make_shared>(std::forward(params)...); addWorkPtr(work); return work; } void addWorkPtr(WorkPtr w); void worker(); using Threads = std::vector; using ToDo = std::deque; ToDo todo; std::counting_semaphore<16> todoLen; std::mutex todoMutex; Threads threads; static Worker instance; };