Files
Seele/src/Engine/ThreadPool.cpp
T

190 lines
4.1 KiB
C++
Raw Normal View History

2021-10-12 14:20:30 +02:00
#include "ThreadPool.h"
2021-12-02 13:00:03 +01:00
#include <memory_resource>
2021-10-12 14:20:30 +02:00
using namespace Seele;
2022-03-26 12:55:04 +01:00
std::mutex Seele::promisesLock;
List<Promise*> Seele::promises;
2021-10-23 00:22:35 +02:00
2021-12-02 13:00:03 +01:00
Event::Event(nullptr_t)
2021-12-15 00:05:42 +01:00
{
}
2021-12-02 13:00:03 +01:00
2022-03-26 12:55:04 +01:00
Event::Event(const std::string &name, const std::source_location &location)
: name(name)
, location(location)
2021-12-15 00:05:42 +01:00
{
}
2021-11-01 20:25:16 +01:00
2022-03-19 22:45:30 +01:00
Event::Event(const std::source_location &location)
2022-03-26 12:55:04 +01:00
: name(location.function_name())
, location(location)
2022-03-19 22:45:30 +01:00
{
}
2021-11-01 20:25:16 +01:00
void Event::raise()
2021-10-23 00:22:35 +02:00
{
2022-03-26 12:55:04 +01:00
std::scoped_lock lock(eventLock);
data = true;
if(waitingJobs.size() > 0)
{
getGlobalThreadPool().scheduleBatch(waitingJobs);
}
if(waitingMainJobs.size() > 0)
{
getGlobalThreadPool().scheduleBatch(waitingMainJobs);
}
2021-11-01 20:25:16 +01:00
}
void Event::reset()
2021-12-15 00:05:42 +01:00
{
2022-03-26 12:55:04 +01:00
std::scoped_lock lock(eventLock);
data = false;
2021-10-23 00:22:35 +02:00
}
2021-10-12 14:20:30 +02:00
2021-11-01 20:25:16 +01:00
bool Event::await_ready()
{
2022-03-26 12:55:04 +01:00
eventLock.lock();
bool result = data;
2022-02-14 16:29:26 +01:00
if(result)
{
2022-03-26 12:55:04 +01:00
eventLock.unlock();
2022-02-14 16:29:26 +01:00
}
return result;
2021-10-12 14:20:30 +02:00
}
2022-03-26 12:55:04 +01:00
void Event::await_suspend(std::coroutine_handle<JobPromiseBase<false>> h)
{
//h.promise().enqueue(this);
waitingJobs.add(JobBase<false>(&h.promise()));
eventLock.unlock();
}
void Event::await_suspend(std::coroutine_handle<JobPromiseBase<true>> h)
{
//h.promise().enqueue(this);
waitingMainJobs.add(JobBase<true>(&h.promise()));
eventLock.unlock();
}
2021-10-12 14:20:30 +02:00
ThreadPool::ThreadPool(uint32 threadCount)
: workers(threadCount)
{
2021-11-01 20:25:16 +01:00
running.store(true);
2021-12-15 00:05:42 +01:00
for (uint32 i = 0; i < threadCount; ++i)
2021-11-01 20:25:16 +01:00
{
2022-03-19 22:45:30 +01:00
workers[i] = std::thread(&ThreadPool::threadLoop, this);
2021-11-01 20:25:16 +01:00
}
2021-10-12 14:20:30 +02:00
}
2021-10-23 00:22:35 +02:00
ThreadPool::~ThreadPool()
2021-10-12 14:20:30 +02:00
{
2022-03-26 12:55:04 +01:00
running.store(false);
{
std::unique_lock lock(mainJobLock);
mainJobCV.notify_all();
}
{
std::unique_lock lock(jobQueueLock);
jobQueueCV.notify_all();
}
for(auto& worker : workers)
{
worker.join();
}
2022-02-14 16:29:26 +01:00
}
2022-03-19 22:45:30 +01:00
void ThreadPool::waitIdle()
2022-02-14 16:29:26 +01:00
{
2022-03-19 22:45:30 +01:00
while(true)
2022-01-12 14:40:26 +01:00
{
2022-03-19 22:45:30 +01:00
std::unique_lock lock(numIdlingLock);
if(numIdling == workers.size())
{
return;
}
2022-03-26 12:55:04 +01:00
numIdlingIncr.wait(lock);
2022-01-12 14:40:26 +01:00
}
2021-10-23 00:22:35 +02:00
}
2022-03-26 12:55:04 +01:00
void ThreadPool::scheduleJob(Job job)
2021-11-01 20:25:16 +01:00
{
2022-03-26 12:55:04 +01:00
assert(!job.done());
2022-01-12 14:40:26 +01:00
std::scoped_lock lock(jobQueueLock);
2022-03-26 12:55:04 +01:00
jobQueue.add(std::move(job));
2022-01-12 14:40:26 +01:00
jobQueueCV.notify_one();
}
2022-03-26 12:55:04 +01:00
void ThreadPool::scheduleJob(MainJob job)
2022-01-12 14:40:26 +01:00
{
2022-03-26 12:55:04 +01:00
assert(!job.done());
2022-01-12 14:40:26 +01:00
std::scoped_lock lock(mainJobLock);
2022-03-26 12:55:04 +01:00
mainJobs.add(std::move(job));
2022-01-12 14:40:26 +01:00
mainJobCV.notify_one();
2021-11-01 20:25:16 +01:00
}
2022-03-19 22:45:30 +01:00
void ThreadPool::mainLoop()
2021-11-19 15:08:56 +01:00
{
2022-03-26 12:55:04 +01:00
while(running.load())
2021-11-19 15:08:56 +01:00
{
2022-03-26 12:55:04 +01:00
MainJob job;
2021-11-19 15:08:56 +01:00
{
2022-03-19 22:45:30 +01:00
std::unique_lock lock(mainJobLock);
if(mainJobs.empty())
2021-12-15 00:05:42 +01:00
{
2022-03-19 22:45:30 +01:00
mainJobCV.wait(lock);
2021-12-15 00:05:42 +01:00
}
2022-03-26 12:55:04 +01:00
[[likely]]
if(!mainJobs.empty())
{
job = mainJobs.front();
mainJobs.popFront();
}
else
{
continue;
}
2022-03-19 22:45:30 +01:00
}
2022-03-26 12:55:04 +01:00
job.resume();
2022-03-19 22:45:30 +01:00
}
}
void ThreadPool::threadLoop()
{
2022-03-26 12:55:04 +01:00
List<Job> localQueue;
while (running.load())
2022-03-19 22:45:30 +01:00
{
[[likely]]
if(!localQueue.empty())
{
2022-03-26 12:55:04 +01:00
Job job = localQueue.retrieve();
job.resume();
2021-11-19 15:08:56 +01:00
}
else
{
2022-03-19 22:45:30 +01:00
std::unique_lock lock(jobQueueLock);
if (jobQueue.empty())
2021-11-01 20:25:16 +01:00
{
2021-12-15 00:05:42 +01:00
{
2022-03-19 22:45:30 +01:00
std::unique_lock lock2(numIdlingLock);
numIdling++;
numIdlingIncr.notify_one();
2021-12-15 00:05:42 +01:00
}
2022-03-19 22:45:30 +01:00
jobQueueCV.wait(lock);
2021-12-15 00:05:42 +01:00
{
2022-03-19 22:45:30 +01:00
std::unique_lock lock2(numIdlingLock);
numIdling--;
2021-12-15 00:05:42 +01:00
}
2021-11-19 15:08:56 +01:00
}
2022-03-19 22:45:30 +01:00
// take 1/numThreads jobs, maybe make this a parameter that
// adjusts based on past workload
2022-03-26 12:55:04 +01:00
uint32 partitionedWorkload = (uint32)(jobQueue.size() / workers.size());
uint32 numTaken = std::clamp(partitionedWorkload, 1u, localQueueSize);
2022-03-19 22:45:30 +01:00
while (!jobQueue.empty() && localQueue.size() < numTaken)
{
localQueue.add(jobQueue.retrieve());
}
2021-11-24 12:10:23 +01:00
}
2021-11-01 20:25:16 +01:00
}
}
2021-12-15 00:05:42 +01:00
ThreadPool &Seele::getGlobalThreadPool()
2021-10-23 00:22:35 +02:00
{
static ThreadPool threadPool;
return threadPool;
2021-10-12 14:20:30 +02:00
}