Path: blob/master/thirdparty/jolt_physics/Jolt/Core/JobSystemThreadPool.h
9906 views
// Jolt Physics Library (https://github.com/jrouwe/JoltPhysics)1// SPDX-FileCopyrightText: 2021 Jorrit Rouwe2// SPDX-License-Identifier: MIT34#pragma once56#include <Jolt/Core/JobSystemWithBarrier.h>7#include <Jolt/Core/FixedSizeFreeList.h>8#include <Jolt/Core/Semaphore.h>910JPH_SUPPRESS_WARNINGS_STD_BEGIN11#include <thread>12JPH_SUPPRESS_WARNINGS_STD_END1314JPH_NAMESPACE_BEGIN1516// Things we're using from STL17using std::thread;1819/// Implementation of a JobSystem using a thread pool20///21/// Note that this is considered an example implementation. It is expected that when you integrate22/// the physics engine into your own project that you'll provide your own implementation of the23/// JobSystem built on top of whatever job system your project uses.24class JPH_EXPORT JobSystemThreadPool final : public JobSystemWithBarrier25{26public:27JPH_OVERRIDE_NEW_DELETE2829/// Creates a thread pool.30/// @see JobSystemThreadPool::Init31JobSystemThreadPool(uint inMaxJobs, uint inMaxBarriers, int inNumThreads = -1);32JobSystemThreadPool() = default;33virtual ~JobSystemThreadPool() override;3435/// Functions to call when a thread is initialized or exits, must be set before calling Init()36using InitExitFunction = function<void(int)>;37void SetThreadInitFunction(const InitExitFunction &inInitFunction) { mThreadInitFunction = inInitFunction; }38void SetThreadExitFunction(const InitExitFunction &inExitFunction) { mThreadExitFunction = inExitFunction; }3940/// Initialize the thread pool41/// @param inMaxJobs Max number of jobs that can be allocated at any time42/// @param inMaxBarriers Max number of barriers that can be allocated at any time43/// @param inNumThreads Number of threads to start (the number of concurrent jobs is 1 more because the main thread will also run jobs while waiting for a barrier to complete). Use -1 to auto detect the amount of CPU's.44void Init(uint inMaxJobs, uint inMaxBarriers, int inNumThreads = -1);4546// See JobSystem47virtual int GetMaxConcurrency() const override { return int(mThreads.size()) + 1; }48virtual JobHandle CreateJob(const char *inName, ColorArg inColor, const JobFunction &inJobFunction, uint32 inNumDependencies = 0) override;4950/// Change the max concurrency after initialization51void SetNumThreads(int inNumThreads) { StopThreads(); StartThreads(inNumThreads); }5253protected:54// See JobSystem55virtual void QueueJob(Job *inJob) override;56virtual void QueueJobs(Job **inJobs, uint inNumJobs) override;57virtual void FreeJob(Job *inJob) override;5859private:60/// Start/stop the worker threads61void StartThreads(int inNumThreads);62void StopThreads();6364/// Entry point for a thread65void ThreadMain(int inThreadIndex);6667/// Get the head of the thread that has processed the least amount of jobs68inline uint GetHead() const;6970/// Internal helper function to queue a job71inline void QueueJobInternal(Job *inJob);7273/// Functions to call when initializing or exiting a thread74InitExitFunction mThreadInitFunction = [](int) { };75InitExitFunction mThreadExitFunction = [](int) { };7677/// Array of jobs (fixed size)78using AvailableJobs = FixedSizeFreeList<Job>;79AvailableJobs mJobs;8081/// Threads running jobs82Array<thread> mThreads;8384// The job queue85static constexpr uint32 cQueueLength = 1024;86static_assert(IsPowerOf2(cQueueLength)); // We do bit operations and require queue length to be a power of 287atomic<Job *> mQueue[cQueueLength];8889// Head and tail of the queue, do this value modulo cQueueLength - 1 to get the element in the mQueue array90atomic<uint> * mHeads = nullptr; ///< Per executing thread the head of the current queue91alignas(JPH_CACHE_LINE_SIZE) atomic<uint> mTail = 0; ///< Tail (write end) of the queue9293// Semaphore used to signal worker threads that there is new work94Semaphore mSemaphore;9596/// Boolean to indicate that we want to stop the job system97atomic<bool> mQuit = false;98};99100JPH_NAMESPACE_END101102103