You're breathtaking!
This commit is contained in:
118
Source/Engine/Threading/ThreadPool.cpp
Normal file
118
Source/Engine/Threading/ThreadPool.cpp
Normal file
@@ -0,0 +1,118 @@
|
||||
// Copyright (c) 2012-2020 Wojciech Figat. All rights reserved.
|
||||
|
||||
#include "ThreadPool.h"
|
||||
#include "IRunnable.h"
|
||||
#include "Threading.h"
|
||||
#include "ThreadPoolTask.h"
|
||||
#include "ConcurrentTaskQueue.h"
|
||||
#include "Engine/Core/Log.h"
|
||||
#include "Engine/Core/Math/Math.h"
|
||||
#include "Engine/Engine/EngineService.h"
|
||||
#include "Engine/Platform/ConditionVariable.h"
|
||||
#include "Engine/Platform/CPUInfo.h"
|
||||
#include "Engine/Platform/Thread.h"
|
||||
|
||||
namespace ThreadPoolImpl
|
||||
{
|
||||
volatile int64 ExitFlag = 0;
|
||||
Array<Thread*> Threads;
|
||||
ConcurrentTaskQueue<ThreadPoolTask> Jobs; // Hello Steve!
|
||||
ConditionVariable JobsSignal;
|
||||
}
|
||||
|
||||
void ThreadPoolTask::Enqueue()
|
||||
{
|
||||
ThreadPoolImpl::Jobs.Add(this);
|
||||
ThreadPoolImpl::JobsSignal.NotifyOne();
|
||||
}
|
||||
|
||||
class ThreadPoolService : public EngineService
|
||||
{
|
||||
public:
|
||||
|
||||
ThreadPoolService()
|
||||
: EngineService(TEXT("Thread Pool"), -900)
|
||||
{
|
||||
}
|
||||
|
||||
bool Init() override;
|
||||
void BeforeExit() override;
|
||||
void Dispose() override;
|
||||
};
|
||||
|
||||
ThreadPoolService ThreadPoolServiceInstance;
|
||||
|
||||
bool ThreadPoolService::Init()
|
||||
{
|
||||
// Spawn threads
|
||||
const int32 numThreads = Math::Max<int32>(2, Platform::GetCPUInfo().ProcessorCoreCount - 1);
|
||||
LOG(Info, "Spawning {0} Thread Pool workers", numThreads);
|
||||
for (int32 i = ThreadPoolImpl::Threads.Count(); i < numThreads; i++)
|
||||
{
|
||||
// Create tread
|
||||
auto runnable = New<SimpleRunnable>(true);
|
||||
runnable->OnWork.Bind(ThreadPool::ThreadProc);
|
||||
auto thread = Thread::Create(runnable, String::Format(TEXT("Therad Pool {0}"), i));
|
||||
if (thread == nullptr)
|
||||
{
|
||||
LOG(Error, "Failed to spawn {0} thread in the Thread Pool", i + 1);
|
||||
return true;
|
||||
}
|
||||
|
||||
// Add to the list
|
||||
ThreadPoolImpl::Threads.Add(thread);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void ThreadPoolService::BeforeExit()
|
||||
{
|
||||
// Set exit flag and wake up threads
|
||||
Platform::AtomicStore(&ThreadPoolImpl::ExitFlag, 1);
|
||||
ThreadPoolImpl::JobsSignal.NotifyAll();
|
||||
}
|
||||
|
||||
void ThreadPoolService::Dispose()
|
||||
{
|
||||
// Set exit flag and wake up threads
|
||||
Platform::AtomicStore(&ThreadPoolImpl::ExitFlag, 1);
|
||||
ThreadPoolImpl::JobsSignal.NotifyAll();
|
||||
|
||||
// Wait some time
|
||||
Platform::Sleep(10);
|
||||
|
||||
// Delete threads
|
||||
for (int32 i = 0; i < ThreadPoolImpl::Threads.Count(); i++)
|
||||
{
|
||||
if (ThreadPoolImpl::Threads[i]->IsRunning())
|
||||
{
|
||||
ThreadPoolImpl::Threads[i]->Kill(true);
|
||||
}
|
||||
}
|
||||
ThreadPoolImpl::Threads.ClearDelete();
|
||||
}
|
||||
|
||||
int32 ThreadPool::ThreadProc()
|
||||
{
|
||||
ThreadPoolTask* task;
|
||||
|
||||
// Work until end
|
||||
CriticalSection mutex;
|
||||
while (Platform::AtomicRead(&ThreadPoolImpl::ExitFlag) == 0)
|
||||
{
|
||||
// Try to get a job
|
||||
if (ThreadPoolImpl::Jobs.try_dequeue(task))
|
||||
{
|
||||
task->Execute();
|
||||
}
|
||||
else
|
||||
{
|
||||
mutex.Lock();
|
||||
ThreadPoolImpl::JobsSignal.Wait(mutex);
|
||||
mutex.Unlock();
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
Reference in New Issue
Block a user