Somewhat fixed thread pool

This commit is contained in:
Dynamitos
2021-12-15 00:05:42 +01:00
parent f4ce5f9585
commit 8ccaa26223
8 changed files with 353 additions and 185 deletions
@@ -75,6 +75,7 @@ MainJob LightCullingPass::beginFrame()
lightEnvDescriptorSet->updateBuffer(2, pointLightBuffer);
lightEnvDescriptorSet->updateBuffer(3, numPointLightBuffer);
lightEnvDescriptorSet->writeChanges();
std::cout << "Finished light culling beginFrame()" << std::endl;
co_return;
}
@@ -60,6 +60,7 @@ void CmdBuffer::end()
void CmdBuffer::beginRenderPass(PRenderPass newRenderPass, PFramebuffer newFramebuffer)
{
assert(state == State::InsideBegin);
std::unique_lock lock(handleLock);
renderPass = newRenderPass;
framebuffer = newFramebuffer;
@@ -87,6 +88,7 @@ void CmdBuffer::executeCommands(const Array<Gfx::PRenderCommand>& commands)
assert(state == State::RenderPassActive);
if(commands.size() == 0)
{
std::cout << "No commands!" << std::endl;
return;
}
std::unique_lock lock(handleLock);
+88 -76
View File
@@ -3,19 +3,20 @@
using namespace Seele;
Event::Event()
: flag(new std::atomic_bool())
{}
: flag(new std::atomic_bool())
{
}
Event::Event(nullptr_t)
: flag(nullptr)
{}
{
}
Event::Event(const std::string& name)
: name(name)
, flag(new std::atomic_bool())
{}
Event::Event(const std::string &name)
: name(name), flag(new std::atomic_bool())
{
}
void Event::raise()
{
@@ -23,7 +24,7 @@ void Event::raise()
getGlobalThreadPool().notify(*this);
}
void Event::reset()
{
{
flag->store(0);
}
@@ -36,7 +37,7 @@ ThreadPool::ThreadPool(uint32 threadCount)
: workers(threadCount)
{
running.store(true);
for(uint32 i = 0; i < threadCount; ++i)
for (uint32 i = 0; i < threadCount; ++i)
{
workers[i] = std::thread(&ThreadPool::threadLoop, this, false);
}
@@ -45,48 +46,52 @@ ThreadPool::ThreadPool(uint32 threadCount)
ThreadPool::~ThreadPool()
{
running.store(false);
for(auto& thread : workers)
for (auto &thread : workers)
{
thread.join();
}
}
void ThreadPool::addJob(Job&& job)
void ThreadPool::enqueueWaiting(Event &event, Promise* job)
{
std::unique_lock lock(jobQueueLock);
//std::cout << "Adding job " << job.id << std::endl;
jobQueue.add(std::move(job));
jobQueueCV.notify_one();
assert(!job->done());
if(event == nullptr)
{
std::unique_lock lock(jobQueueLock);
jobQueue.add(job);
jobQueueCV.notify_one();
}
else
{
std::unique_lock lock(waitingLock);
waitingJobs[event].add(job);
}
}
void ThreadPool::addJob(MainJob&& job)
void ThreadPool::enqueueWaiting(Event &event, MainPromise* job)
{
std::unique_lock lock(mainJobLock);
//std::cout << "Adding main job " << job.id << std::endl;
mainJobs.add(std::move(job));
mainJobCV.notify_one();
assert(!job->done());
if(event == nullptr)
{
std::unique_lock lock(mainJobLock);
mainJobs.add(job);
mainJobCV.notify_one();
}
else
{
std::unique_lock lock(waitingMainLock);
waitingMainJobs[event].add(job);
}
}
void ThreadPool::enqueueWaiting(Event& event, Job&& job)
{
//std::cout << job.id << " waiting for event " << event.name << std::endl;
std::unique_lock lock(waitingLock);
waitingJobs[event].add(std::move(job));
}
void ThreadPool::enqueueWaiting(Event& event, MainJob&& job)
{
//std::cout << job.id << " main waiting for event " << event.name << std::endl;
std::unique_lock lock(waitingMainLock);
waitingMainJobs[event].add(std::move(job));
}
void ThreadPool::notify(Event& event)
void ThreadPool::notify(Event &event)
{
{
std::unique_lock lock(jobQueueLock);
std::unique_lock lock2(waitingLock);
List<Job>& jobs = waitingJobs[event];
for(auto& job : jobs)
List<Promise*> &jobs = waitingJobs[event];
for (auto &job : jobs)
{
//assert(job.id != -1ull);
//std::cout << "Waking up job " << job.id << std::endl;
jobQueue.add(std::move(job));
jobQueue.add(job);
jobQueueCV.notify_one();
}
jobs.clear();
@@ -94,67 +99,74 @@ void ThreadPool::notify(Event& event)
{
std::unique_lock lock(mainJobLock);
std::unique_lock lock2(waitingMainLock);
List<MainJob>& jobs = waitingMainJobs[event];
for(auto& job : jobs)
List<MainPromise*> &jobs = waitingMainJobs[event];
for (auto &job : jobs)
{
//assert(job.id != -1ull);
//std::cout << "Waking up main job " << job.id << std::endl;
mainJobs.add(std::move(job));
mainJobs.add(job);
mainJobCV.notify_one();
}
jobs.clear();
}
}
void ThreadPool::tryMainJob()
void ThreadPool::threadLoop(const bool mainThread)
{
MainJob job;
while (running.load())
{
std::unique_lock lock(mainJobLock);
if(!mainJobs.empty())
if (mainThread)
{
job = std::move(mainJobs.retrieve());
MainPromise* job;
{
std::unique_lock lock(mainJobLock);
if(mainJobs.empty())
{
mainJobCV.wait(lock);
}
if (!mainJobs.empty())
{
job = mainJobs.retrieve();
}
else
{
continue;
}
}
job->resume();
if (job->done())
{
job->raise();
}
}
else
{
return;
}
}
job.resume();
}
void ThreadPool::threadLoop(const bool mainThread)
{
while(running.load())
{
if(mainThread)
{
tryMainJob();
}
Job job;
{
std::unique_lock lock(jobQueueLock);
if(jobQueue.empty())
Promise* job;
{
jobQueueCV.wait(lock);
std::unique_lock lock(jobQueueLock);
if (jobQueue.empty())
{
jobQueueCV.wait(lock);
}
if (!jobQueue.empty())
{
job = jobQueue.retrieve();
}
else
{
continue;
}
}
if(!jobQueue.empty())
//std::cout << "Starting job " << job.id << std::endl;
job->resume();
if (job->done())
{
job = std::move(jobQueue.retrieve());
job->raise();
}
else
{
continue;
}
}
//std::cout << "Starting job " << job.id << std::endl;
job.resume();
if(job.done())
{
job.raise();
}
}
}
ThreadPool& Seele::getGlobalThreadPool()
ThreadPool &Seele::getGlobalThreadPool()
{
static ThreadPool threadPool;
return threadPool;
+128 -98
View File
@@ -8,29 +8,8 @@
namespace Seele
{
extern class ThreadPool& getGlobalThreadPool();
template<bool MainJob>
struct JobBase;
struct Event;
static std::atomic_uint64_t globalCounter;
template<bool MainJob>
struct JobPromiseBase
{
JobBase<MainJob> get_return_object() noexcept;
inline auto initial_suspend() noexcept;
inline auto final_suspend() const noexcept;
void return_void() noexcept {}
void unhandled_exception() noexcept {
std::cerr << "Unhandled exception" << std::endl;
exit(1);
};
std::coroutine_handle<> continuation = std::noop_coroutine();
uint64 id;
Event finishedEvent;
};
struct JobPromiseBase;
struct Event
{
public:
@@ -41,6 +20,10 @@ public:
{
return flag <=> other.flag;
}
bool operator==(const Event& other) const
{
return flag == other.flag;
}
Event operator co_await()
{
return *this;
@@ -62,65 +45,43 @@ private:
friend class ThreadPool;
};
template<bool MainJob = false>
struct JobBase
static std::atomic_uint64_t globalCounter;
template<bool MainJob>
struct JobBase;
template<bool MainJob>
struct JobPromiseBase
{
public:
using promise_type = JobPromiseBase<MainJob>;
explicit JobBase()
: id(-1)
JobPromiseBase()
{
handle = std::coroutine_handle<JobPromiseBase<MainJob>>::from_promise(*this);
id = globalCounter++;
finishedEvent = Event(std::format("Job {}", id));
}
explicit JobBase(std::coroutine_handle<promise_type> handle, uint64 id, Event finishedEvent)
: handle(handle)
, event(std::move(finishedEvent))
, id(id)
{
}
JobBase(const JobBase & rhs) = delete;
JobBase(JobBase&& rhs)
: handle(std::move(rhs.handle))
, event(rhs.event)
, id(std::move(rhs.id))
{
rhs.id = -1;
rhs.handle = nullptr;
}
~JobBase()
{
if(handle && handle.done())
{
std::cout << "Destroy job " << handle.address() << std::endl;
handle.destroy();
}
}
JobBase& operator=(const JobBase& rhs) = delete;
JobBase& operator=(JobBase&& rhs)
{
if(this != &rhs)
{
handle = std::move(rhs.handle);
event = std::move(rhs.event);
id = std::move(rhs.id);
rhs.id = -1;
rhs.handle = nullptr;
}
return *this;
}
JobBase<MainJob> get_return_object() noexcept;
inline auto initial_suspend() noexcept;
inline auto final_suspend() const noexcept;
void return_void() noexcept {}
void unhandled_exception() noexcept {
std::cerr << "Unhandled exception" << std::endl;
exit(1);
};
void resume()
{
handle.resume();
std::unique_lock lock(promiseLock);
if(handle && !handle.done())
{
handle.resume();
}
}
template<std::invocable Callable>
inline JobBase then(Callable callable)
void setContinuation(JobPromiseBase* cont)
{
return then(callable());
}
JobBase then(JobBase continuation)
{
handle.promise().continuation = continuation.handle;
return continuation;
std::unique_lock lock(promiseLock);
std::unique_lock lock2(cont->promiseLock);
continuation = cont->handle;
cont->precondition = finishedEvent;
}
bool done()
{
@@ -128,15 +89,87 @@ public:
}
void raise()
{
event.raise();
std::unique_lock lock(promiseLock);
finishedEvent.raise();
}
void reset()
{
event.reset();
std::unique_lock lock(promiseLock);
finishedEvent.reset();
}
void enqueue(Event& event)
{
getGlobalThreadPool().enqueueWaiting(event, this);
}
void schedule()
{
std::unique_lock lock(promiseLock);
if(!handle || handle.done())
{
return;
}
getGlobalThreadPool().enqueueWaiting(precondition, this);
}
std::mutex promiseLock;
std::coroutine_handle<JobPromiseBase> handle;
std::coroutine_handle<> continuation = std::noop_coroutine();
uint64 id;
Event finishedEvent;
Event precondition = nullptr;
};
template<bool MainJob = false>
struct JobBase
{
public:
using promise_type = JobPromiseBase<MainJob>;
explicit JobBase()
: promise(nullptr)
{
}
explicit JobBase(JobPromiseBase<MainJob>* promise)
: promise(promise)
{
}
~JobBase()
{
if(promise)
{
promise->schedule();
}
}
void resume()
{
promise->resume();
}
template<std::invocable Callable>
inline JobBase then(Callable callable)
{
return then(callable());
}
JobBase then(JobBase&& continuation)
{
promise->setContinuation(continuation.promise);
return continuation;
}
bool done()
{
return promise->done();
}
void raise()
{
promise->raise();
}
void reset()
{
promise->reset();
}
Event operator co_await()
{
return event;
promise->resume();
return promise->finishedEvent;
}
static JobBase all() = delete;
template<typename... Awaitable>
@@ -166,58 +199,54 @@ public:
}
}
private:
std::coroutine_handle<promise_type> handle;
Event event;
uint64 id;
JobPromiseBase<MainJob>* promise;
};
using MainJob = JobBase<true>;
using Job = JobBase<false>;
using MainPromise = JobPromiseBase<true>;
using Promise = JobPromiseBase<false>;
class ThreadPool
{
public:
ThreadPool(uint32 threadCount = std::thread::hardware_concurrency());
virtual ~ThreadPool();
void addJob(Job&& job);
void addJob(MainJob&& job);
void enqueueWaiting(Event& event, Job&& job);
void enqueueWaiting(Event& event, MainJob&& job);
// Adds a job to the waiting queue for event, or directly to the job queue if event is nullptr
void enqueueWaiting(Event& event, Promise* job);
// Adds a job to the waiting queue for event, or directly to the job queue if event is nullptr
void enqueueWaiting(Event& event, MainPromise* job);
void notify(Event& event);
void threadLoop(const bool isMainThread);
private:
std::atomic_bool running;
std::vector<std::thread> workers;
List<MainJob> mainJobs;
List<MainPromise*> mainJobs;
std::mutex mainJobLock;
std::condition_variable mainJobCV;
List<Job> jobQueue;
List<Promise*> jobQueue;
std::mutex jobQueueLock;
std::condition_variable jobQueueCV;
Map<Event, List<Job>> waitingJobs;
std::mutex waitingLock;
Map<Event, List<MainJob>> waitingMainJobs;
Map<Event, List<MainPromise*>> waitingMainJobs;
std::mutex waitingMainLock;
void tryMainJob();
};
Map<Event, List<Promise*>> waitingJobs;
std::mutex waitingLock;
};
template<bool MainJob>
inline JobBase<MainJob> JobPromiseBase<MainJob>::get_return_object() noexcept
{
id = globalCounter++;
return JobBase<MainJob>(std::coroutine_handle<JobPromiseBase<MainJob>>::from_promise(*this), id, finishedEvent);
return JobBase<MainJob>(this);
}
template<bool MainJob>
inline auto JobPromiseBase<MainJob>::initial_suspend() noexcept
{
struct JobAwaitable
/*struct JobAwaitable
{
constexpr bool await_ready() { return false; }
constexpr void await_suspend(std::coroutine_handle<JobPromiseBase<MainJob>> h)
@@ -228,7 +257,8 @@ inline auto JobPromiseBase<MainJob>::initial_suspend() noexcept
uint64 id;
Event& event;
};
return JobAwaitable{id, finishedEvent};
return JobAwaitable{id, finishedEvent};*/
return std::suspend_always{};
}
template<bool MainJob>
inline auto JobPromiseBase<MainJob>::final_suspend() const noexcept
@@ -248,7 +278,7 @@ inline auto JobPromiseBase<MainJob>::final_suspend() const noexcept
template<bool MainJob>
inline constexpr void Event::await_suspend(std::coroutine_handle<JobPromiseBase<MainJob>> h)
{
getGlobalThreadPool().enqueueWaiting(*this, std::move(JobBase<MainJob>(h, h.promise().id, *this)));
h.promise().enqueue(*this);
}
} // namespace Seele
+3 -3
View File
@@ -93,11 +93,11 @@ MainJob SceneView::render()
.then(depthPrepass.endFrame())
.then(lightCullingPass.endFrame())
.then(basePass.endFrame())
.then([=]() -> MainJob
.then([&](Event& event) -> MainJob
{
renderFinishedEvent.raise();
event.raise();
co_return;
});
}(renderFinishedEvent));
}
void SceneView::keyCallback(KeyCode code, InputAction action, KeyModifier)
+5 -1
View File
@@ -43,7 +43,11 @@ MainJob Window::render()
windowView->view->resetRender();
}
gfxHandle->endFrame();
render();
if(owner->isActive())
{
render();
}
co_return;
}
Gfx::PWindow Window::getGfxHandle()
+6 -4
View File
@@ -19,7 +19,7 @@ int main()
mainWindowInfo.pixelFormat = Gfx::SE_FORMAT_B8G8R8A8_UNORM;
auto window = windowManager->addWindow(mainWindowInfo);
ViewportCreateInfo sceneViewInfo;
sceneViewInfo.sizeX = 640;
sceneViewInfo.sizeX = 1280;
sceneViewInfo.sizeY = 720;
sceneViewInfo.offsetX = 0;
sceneViewInfo.offsetY = 0;
@@ -31,10 +31,12 @@ int main()
inspectorViewInfo.sizeY = 720;
inspectorViewInfo.offsetX = 640;
inspectorViewInfo.offsetY = 0;
PInspectorView inspectorView = new InspectorView(windowManager->getGraphics(), window, inspectorViewInfo);
window->addView(inspectorView);
//PInspectorView inspectorView = new InspectorView(windowManager->getGraphics(), window, inspectorViewInfo);
//window->addView(inspectorView);
sceneView->setFocused();
window->render();
{
window->render();
}
getGlobalThreadPool().threadLoop(true);
return 0;
}