EntropyEngine::Core::Concurrency::WorkService
EntropyEngine::Core::Concurrency::WorkService
Section titled “EntropyEngine::Core::Concurrency::WorkService”Thread pool service that executes work contracts from multiple groups. More…
#include <WorkService.h>
Inherits from EntropyEngine::Core::Concurrency::IConcurrencyProvider, EntropyEngine::Core::EntropyService, EntropyEngine::Core::EntropyObject
Public Classes
Section titled “Public Classes”| Name | |
|---|---|
| struct | MainThreadWorkResult Result structure for main thread work execution. |
| struct | Config Configuration parameters for the work service. |
Public Types
Section titled “Public Types”| Name | |
|---|---|
| enum class | GroupOperationStatus { Removed = 1, OutOfSpace = 2, NotFound = 4, Exists = 3, Added = 0} |
Public Functions
Section titled “Public Functions”| Name | |
|---|---|
| ~WorkService() Destroys the work service and cleans up all resources. | |
| void | waitForStop() Waits for all worker threads to finish (blocking). |
| virtual const char * | version() const override |
| virtual void | unload() override |
| virtual TypeSystem::TypeID | typeId() const override |
| virtual void | stop() override Stops all worker threads and waits for them to finish. |
| virtual void | start() override Starts the worker threads and begins executing work. |
| size_t | setSoftFailureCount(size_t softFailureCount) |
| size_t | setFailureSleepTime(size_t failureSleepTime) Sets how long the system will sleep a thread (in nanoseconds). |
| void | resetThreadLocalState() Reset static thread-local variables (for testing only). |
| void | requestStop() Signals all worker threads to stop (non-blocking). |
| GroupOperationStatus | removeWorkContractGroup(WorkContractGroup * contractGroup) Unregisters a work group from the service. |
| virtual void | notifyWorkAvailable(WorkContractGroup * group =nullptr) override Notifies the provider that work may be available. |
| virtual void | notifyGroupDestroyed(WorkContractGroup * group) override Called when a group is being destroyed. |
| virtual const char * | name() const override |
| virtual void | load() override |
| bool | isRunning() const |
| virtual const char * | id() const override |
| bool | hasMainThreadWork() const Check if any registered group has main thread work available. |
| size_t | getWorkContractGroupCount() const Gets the current work contract group count. |
| size_t | getThreadCount() const The current thread count. |
| size_t | getSoftFailureCount() const |
| size_t | getFailureSleepTime() const Gets how long the system will sleep a thread (in nanoseconds). |
| MainThreadWorkResult | executeMainThreadWork(size_t maxContracts =std::numeric_limits< size_t >::max()) Execute main thread targeted work from all registered groups. |
| size_t | executeMainThreadWork(WorkContractGroup * group, size_t maxContracts =std::numeric_limits< size_t >::max()) Execute main thread work from a specific group. |
| virtual std::vector< TypeSystem::TypeID > | dependsOnTypes() const override |
| virtual std::vector< std::string > | dependsOn() const override |
| void | clear() Removes all registered work groups (only when stopped). |
| GroupOperationStatus | addWorkContractGroup(WorkContractGroup * contractGroup) Registers a work group with the service so it can be scheduled. |
| WorkService(Config config, std::unique_ptr< IWorkScheduler > scheduler =nullptr) Creates a work service with the specified configuration. |
Additional inherited members
Section titled “Additional inherited members”Public Functions inherited from EntropyEngine::Core::Concurrency::IConcurrencyProvider
| Name | |
|---|---|
| virtual | ~IConcurrencyProvider() =default |
| virtual void | notifyMainThreadWorkAvailable(WorkContractGroup * group =nullptr) Notifies the provider that main thread work may be available. |
Public Functions inherited from EntropyEngine::Core::EntropyService
| Name | |
|---|---|
| ~EntropyService() override =default | |
| ServiceState | state() const |
| virtual const char * | className() const override Runtime class name for diagnostics and reflection. |
Protected Functions inherited from EntropyEngine::Core::EntropyService
| Name | |
|---|---|
| void | setState(ServiceState s) |
Friends inherited from EntropyEngine::Core::EntropyService
| Name | |
|---|---|
| class | EntropyServiceRegistry |
Protected Classes inherited from EntropyEngine::Core::EntropyObject
| Name | |
|---|---|
| struct | HandleCore Optional handle identity stamped by an owner/registry. |
Public Functions inherited from EntropyEngine::Core::EntropyObject
| Name | |
|---|---|
| virtual | ~EntropyObject() =default |
| virtual const TypeSystem::TypeInfo * | typeInfo() const Optional richer type information; may be null. |
| bool | tryRetain() const Attempts to retain only if the object is still alive. |
| virtual std::string | toString() const Human-readable short string (class@ptr by default). |
| void | retain() const Increments the reference count. |
| void | release() const Decrements the reference count and deletes when it reaches zero. |
| uint32_t | refCount() const Current reference count (approximate under contention). |
| EntropyObject & | operator=(const EntropyObject & ) =delete |
| EntropyObject & | operator=(EntropyObject && ) =delete |
| bool | hasHandle() const |
| template <class OwnerT > OwnerT * | handleOwnerAs() const Returns the stamped owner pointer cast to the requested type. |
| const void * | handleOwner() const |
| uint32_t | handleIndex() const |
| uint64_t | handleId() const |
| uint32_t | handleGeneration() const |
| WeakControlBlock * | getWeakControlBlock() const Lazily retrieves or creates the weak control block. |
| virtual std::string | description() const Long-form description; defaults to toString(). |
| virtual std::string | debugString() const Debug-oriented string including refcount and handle when present. |
| virtual const char * | className() const Runtime class name for diagnostics and reflection. |
| virtual uint64_t | classHash() const Stable type hash for cross-language identification. |
| EntropyObject() =default | |
| EntropyObject(EntropyObject && ) =delete | |
| EntropyObject(const EntropyObject & ) =delete |
Protected Functions inherited from EntropyEngine::Core::EntropyObject
| Name | |
|---|---|
| void | _setHandleIdentity(void * owner, uint32_t index, uint32_t generation) |
| void | _clearHandleIdentity() |
Protected Attributes inherited from EntropyEngine::Core::EntropyObject
| Name | |
|---|---|
| std::atomic< WeakControlBlock * > | _weakBlock Lazily allocated control block for weak refs. |
| std::atomic< uint32_t > | _refCount Thread-safe retain/release counter. |
| struct EntropyEngine::Core::EntropyObject::HandleCore | _handle |
Friends inherited from EntropyEngine::Core::EntropyObject
| Name | |
|---|---|
| struct | HandleAccess |
Detailed Description
Section titled “Detailed Description”class EntropyEngine::Core::Concurrency::WorkService;Thread pool service that executes work contracts from multiple groups.
Think of WorkService as a team of workers (threads) that grab tasks from different departments (WorkContractGroups). Each department has its own queue of work, and the workers use a pluggable scheduler to decide which department needs help most.
The service delegates all scheduling decisions to an IWorkScheduler implementation, allowing you to experiment with different scheduling strategies without modifying the core thread management logic.
Perfect for:
- Game engines that need to balance rendering, physics, AI, and audio work
- Servers that handle different types of requests with varying priorities
- Any system with multiple independent work producers that need fair execution
Key features:
- Lock-free work execution (groups handle their own synchronization)
- Pluggable scheduling strategies via IWorkScheduler interface
- Thread pool management independent of scheduling logic
- No work stealing between groups (intentional for data isolation)
// Create service with adaptive ranking scheduler (default)WorkService::Config config;config.threadCount = 8;WorkService service(config);
// Or use a custom schedulerauto scheduler = std::make_unique<RoundRobinScheduler>(schedulerConfig);WorkService service(config, std::move(scheduler));
// Add work groups from different systemsservice.addWorkContractGroup(&renderingGroup);service.addWorkContractGroup(&physicsGroup);service.addWorkContractGroup(&audioGroup);
// Start the workersservice.start();
// Systems submit work through their groups, service handles distribution// ...
// Shutdown when doneservice.stop();Public Types Documentation
Section titled “Public Types Documentation”enum GroupOperationStatus
Section titled “enum GroupOperationStatus”| Enumerator | Value | Description |
|---|---|---|
| Removed | 1 | |
| OutOfSpace | 2 | |
| NotFound | 4 | |
| Exists | 3 | |
| Added | 0 |
Public Functions Documentation
Section titled “Public Functions Documentation”function ~WorkService
Section titled “function ~WorkService”~WorkService()Destroys the work service and cleans up all resources.
Automatically calls stop() if the service is still running, waits for all threads to finish, then cleans up. Safe to call even if service was never started.
function waitForStop
Section titled “function waitForStop”void waitForStop()Waits for all worker threads to finish (blocking).
Blocks the calling thread until all worker threads have completed execution. Should be called after requestStop() if you need to ensure all threads have finished before proceeding.
service.waitForStop(); // Wait for all threads to finishfunction version
Section titled “function version”inline virtual const char * version() const overrideReimplements: EntropyEngine::Core::EntropyService::version
function unload
Section titled “function unload”inline virtual void unload() overrideReimplements: EntropyEngine::Core::EntropyService::unload
function typeId
Section titled “function typeId”inline virtual TypeSystem::TypeID typeId() const overrideReimplements: EntropyEngine::Core::EntropyService::typeId
function stop
Section titled “function stop”virtual void stop() overrideStops all worker threads and waits for them to finish.
Reimplements: EntropyEngine::Core::EntropyService::stop
Convenience method that calls requestStop() followed by waitForStop(). This is a blocking call that ensures all threads have completed before returning.
service.stop(); // Stop and wait for all threads (blocking)function start
Section titled “function start”virtual void start() overrideStarts the worker threads and begins executing work.
Reimplements: EntropyEngine::Core::EntropyService::start
Spawns the configured number of worker threads, each running the adaptive scheduling algorithm. Safe to call multiple times - if already running, does nothing.
service.start(); // Workers now actively looking for workfunction setSoftFailureCount
Section titled “function setSoftFailureCount”size_t setSoftFailureCount( size_t softFailureCount)function setFailureSleepTime
Section titled “function setFailureSleepTime”size_t setFailureSleepTime( size_t failureSleepTime)Sets how long the system will sleep a thread (in nanoseconds).
Parameters:
- failureSleepTime How long to sleep a thread for (in nanoseconds).
Return: How long the system will now sleep a thread for (in nanoseconds).
function resetThreadLocalState
Section titled “function resetThreadLocalState”static void resetThreadLocalState()Reset static thread-local variables (for testing only).
Warning: This should only be used in test environments to ensure clean state between tests
function requestStop
Section titled “function requestStop”void requestStop()Signals all worker threads to stop (non-blocking).
Requests workers to stop without waiting. Returns immediately while workers complete their current contract before stopping.
service.requestStop(); // Signal workers to stop (non-blocking)function removeWorkContractGroup
Section titled “function removeWorkContractGroup”GroupOperationStatus removeWorkContractGroup( WorkContractGroup * contractGroup)Unregisters a work group from the service.
Parameters:
- contractGroup The group to remove - must be currently registered
Return: Removed if successful, NotFound if group wasn’t registered
Removes a group from the scheduling rotation. Any work already in the group remains there - this just stops the service from checking it for new work.
Important: This takes a lock and might block. Best practice is to remove groups during shutdown or when a system is being disabled, not during active execution.
// Clean up during system shutdownservice.removeWorkContractGroup(&physicsGroup);function notifyWorkAvailable
Section titled “function notifyWorkAvailable”virtual void notifyWorkAvailable( WorkContractGroup * group =nullptr) overrideNotifies the provider that work may be available.
Parameters:
- group The group that has new work available (optional, for routing)
Reimplements: EntropyEngine::Core::Concurrency::IConcurrencyProvider::notifyWorkAvailable
Called by WorkContractGroup when new work is scheduled. The provider should wake up any waiting threads to check for work. This is just a hint - the work may have already been consumed by the time a thread wakes up.
function notifyGroupDestroyed
Section titled “function notifyGroupDestroyed”virtual void notifyGroupDestroyed( WorkContractGroup * group) overrideCalled when a group is being destroyed.
Parameters:
- group The group being destroyed
Reimplements: EntropyEngine::Core::Concurrency::IConcurrencyProvider::notifyGroupDestroyed
Allows the provider to clean up any references to the group. After this call, the provider must not access the group pointer.
function name
Section titled “function name”inline virtual const char * name() const overrideReimplements: EntropyEngine::Core::EntropyService::name
function load
Section titled “function load”inline virtual void load() overrideReimplements: EntropyEngine::Core::EntropyService::load
function isRunning
Section titled “function isRunning”bool isRunning() constfunction id
Section titled “function id”inline virtual const char * id() const overrideReimplements: EntropyEngine::Core::EntropyService::id
function hasMainThreadWork
Section titled “function hasMainThreadWork”bool hasMainThreadWork() constCheck if any registered group has main thread work available.
Return: true if at least one group has main thread work scheduled
Quick non-blocking check to determine if you need to pump main thread work. Use this to avoid unnecessary calls to executeMainThreadWork().
// Only pump if there's work to doif (service.hasMainThreadWork()) { service.executeMainThreadWork(frameWorkBudget);}function getWorkContractGroupCount
Section titled “function getWorkContractGroupCount”size_t getWorkContractGroupCount() constGets the current work contract group count.
Return: How many work contract groups that are currently registered in the work service.
This will return however many work gcontract groups that are currently registered in the work service. You should use this to check to make sure that there is room to actually register your work contract group, as the work service does not dynamically reallocate its pool of work contract groups.
This is intentional to better force right sizing of the group.
auto currentWorkGroupCount = workService.getWorkContractGroupCount();if (currentWorkGroupCount < workService.getMaxWorkGroups() -1) workService.addWorkContractGroup(&contractGroup);function getThreadCount
Section titled “function getThreadCount”size_t getThreadCount() constThe current thread count.
Return: The thread count.
Ranges from 1 to max concurrency.
function getSoftFailureCount
Section titled “function getSoftFailureCount”size_t getSoftFailureCount() constfunction getFailureSleepTime
Section titled “function getFailureSleepTime”size_t getFailureSleepTime() constGets how long the system will sleep a thread (in nanoseconds).
Return: How many nanoseconds the system will sleep a thread for after all hard retries have been exhausted.
function executeMainThreadWork
Section titled “function executeMainThreadWork”MainThreadWorkResult executeMainThreadWork( size_t maxContracts =std::numeric_limits< size_t >::max())Execute main thread targeted work from all registered groups.
Parameters:
- maxContracts Maximum number of contracts to execute (default: unlimited)
Return: MainThreadWorkResult with execution statistics
Call from your main thread to process UI, rendering, or other main-thread-only work. Distributes execution fairly across groups. Use maxContracts to limit work per frame and maintain responsiveness.
// Game loop with frame budgetvoid gameUpdate() { // Process up to 10 main thread tasks per frame auto result = service.executeMainThreadWork(10);
if (result.moreWorkAvailable) { // More work pending - will process next frame needsUpdate = true; }
// Continue with rendering render();}function executeMainThreadWork
Section titled “function executeMainThreadWork”size_t executeMainThreadWork( WorkContractGroup * group, size_t maxContracts =std::numeric_limits< size_t >::max())Execute main thread work from a specific group.
Parameters:
- group The group to execute work from
- maxContracts Maximum number of contracts to execute
Return: Number of contracts executed
Use when you need fine-grained control over which group’s work executes. Useful for prioritizing certain subsystems over others.
// Prioritize UI work over other main thread taskssize_t uiWork = service.executeMainThreadWork(&uiGroup, 5);size_t otherWork = service.executeMainThreadWork(&miscGroup, 2);function dependsOnTypes
Section titled “function dependsOnTypes”inline virtual std::vector< TypeSystem::TypeID > dependsOnTypes() const overrideReimplements: EntropyEngine::Core::EntropyService::dependsOnTypes
function dependsOn
Section titled “function dependsOn”inline virtual std::vector< std::string > dependsOn() const overrideReimplements: EntropyEngine::Core::EntropyService::dependsOn
function clear
Section titled “function clear”void clear()Removes all registered work groups (only when stopped).
Nuclear option that unregisters all groups at once. Only works when the service is stopped to prevent race conditions. Mainly useful for testing or complete system resets.
service.stop();service.clear(); // All groups unregistered// Re-add groups and restart...function addWorkContractGroup
Section titled “function addWorkContractGroup”GroupOperationStatus addWorkContractGroup( WorkContractGroup * contractGroup)Registers a work group with the service so it can be scheduled.
Parameters:
- contractGroup Pointer to the group to add - must remain valid while registered
Return: Added if successful, OutOfSpace if at capacity, Exists if already registered
Think of this as adding a new department to your worker pool. Once registered, the group will be included in the ranking algorithm and its work will be executed by the service’s threads.
Important: This takes a lock and might block briefly. Best practice is to register all your groups during initialization, not during active execution. The service pre-allocates space for maxWorkGroups to avoid resizing.
// Register groups during startupif (service.addWorkContractGroup(&physicsGroup) != GroupOperationStatus::Added) { LOG_ERROR("Failed to register physics work group");}function WorkService
Section titled “function WorkService”explicit WorkService( Config config, std::unique_ptr< IWorkScheduler > scheduler =nullptr)Creates a work service with the specified configuration.
Parameters:
- config Service configuration - see Config struct for tuning options
- scheduler Optional custom scheduler (uses AdaptiveRankingScheduler if nullptr)
The service is created in a stopped state. You must call start() to begin executing work. Thread count is clamped to hardware concurrency, so asking for 1000 threads on an 8-core machine gets you 8 threads.
Uses AdaptiveRankingScheduler by default if no scheduler is provided.
// Use default adaptive ranking schedulerWorkService::Config config;config.threadCount = 0; // Use all CPU coresWorkService service(config);
// Or provide a custom schedulerauto scheduler = std::make_unique<RoundRobinScheduler>(schedulerConfig);WorkService service(config, std::move(scheduler));Updated on 2026-01-26 at 16:50:32 -0500