EntropyEngine::Core::Concurrency::WorkContractGroup
EntropyEngine::Core::Concurrency::WorkContractGroup
Section titled “EntropyEngine::Core::Concurrency::WorkContractGroup”Factory and manager for work contracts with lock-free scheduling. More…
#include <WorkContractGroup.h>
Inherits from EntropyEngine::Core::EntropyObject
Public Types
Section titled “Public Types”| Name | |
|---|---|
| using std::list< std::function< void()> >::iterator | CapacityCallback |
Public Functions
Section titled “Public Functions”| Name | |
|---|---|
| ~WorkContractGroup() Destructor ensures all work is stopped and completed. | |
| void | wait() Waits for all scheduled and executing contracts to complete. |
| ScheduleResult | unscheduleContract(const WorkContractHandle & handle) Removes a contract from scheduling (called by handle.unschedule()). |
| virtual std::string | toString() const override Human-readable short string (class@ptr by default). |
| void | stop() Stops the group from accepting new work selections. |
| void | setTimedDeferralCallback(std::function< size_t()> callback) Sets a callback for checking timed deferrals. |
| void | setConcurrencyProvider(IConcurrencyProvider * provider) Associates this group with a concurrency provider. |
| WorkContractHandle | selectForMainThreadExecution(std::optional< std::reference_wrapper< uint64_t > > bias =std::nullopt) Selects a main thread scheduled contract for execution. |
| WorkContractHandle | selectForExecution(std::optional< std::reference_wrapper< uint64_t > > bias =std::nullopt) Selects a scheduled contract for execution. |
| size_t | scheduledCount() const Gets the number of contracts currently scheduled for execution. |
| ScheduleResult | scheduleContract(const WorkContractHandle & handle) Schedules a contract for execution (called by handle.schedule()). |
| void | resume() Resumes the group to allow new work selections. |
| void | removeOnCapacityAvailable(CapacityCallback it) Remove a capacity available callback. |
| void | releaseContract(const WorkContractHandle & handle) Immediately releases a contract (called by handle.release()). |
| WorkContractGroup & | operator=(const WorkContractGroup & ) =delete |
| WorkContractGroup & | operator=(WorkContractGroup && other) |
| size_t | mainThreadScheduledCount() const Gets the number of main thread contracts currently scheduled. |
| size_t | mainThreadExecutingCount() const Gets the number of main thread contracts currently executing. |
| bool | isValidHandle(const WorkContractHandle & handle) const Validates a handle belongs to this group (called by handle.valid()). |
| bool | isStopping() const Checks if the group is in the process of stopping. |
| bool | hasMainThreadWork() const Checks if there are any main thread contracts ready to execute. |
| ContractState | getContractState(const WorkContractHandle & handle) const Gets the current state of a contract. |
| IConcurrencyProvider * | getConcurrencyProvider() const Gets the currently associated concurrency provider. |
| size_t | executingCount() const Returns the current number of contracts being actively executed. |
| size_t | executeMainThreadWork(size_t maxContracts) Executes main thread targeted work contracts with a limit. |
| void | executeContract(const WorkContractHandle & handle) Executes the work function of a contract. |
| size_t | executeAllMainThreadWork() Executes all main thread targeted work contracts. |
| void | executeAllBackgroundWork() Executes all background (non-main-thread) contracts sequentially in the calling thread. |
| virtual std::string | description() const override Long-form description; defaults to toString(). |
| virtual std::string | debugString() const override Debug-oriented string including refcount and handle when present. |
| WorkContractHandle | createContract(std::function< void()> work, ExecutionType executionType =ExecutionType::AnyThread) Creates a new work contract with the given work function. |
| void | completeMainThreadExecution(const WorkContractHandle & handle) Completes execution and cleans up a main thread contract. |
| void | completeExecution(const WorkContractHandle & handle) Completes execution and cleans up a contract. |
| virtual const char * | className() const override Runtime class name for diagnostics and reflection. |
| virtual uint64_t | classHash() const override Stable type hash for cross-language identification. |
| size_t | checkTimedDeferrals() Checks for timed deferrals and schedules ready nodes. |
| size_t | capacity() const Gets the maximum capacity of this group. |
| CapacityCallback | addOnCapacityAvailable(std::function< void()> callback) Add a callback to be invoked when capacity becomes available. |
| size_t | activeCount() const Gets the number of currently allocated contracts. |
| void | abortExecution(const WorkContractHandle & handle) Aborts execution without running the task (shutdown-only path). |
| WorkContractGroup(size_t capacity, std::string name =“WorkContractGroup”) Constructs a work contract group with specified capacity. | |
| WorkContractGroup(const WorkContractGroup & ) =delete | |
| WorkContractGroup(WorkContractGroup && other) |
Additional inherited members
Section titled “Additional inherited members”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. |
| 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). |
| 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. |
| 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::WorkContractGroup;Factory and manager for work contracts with lock-free scheduling.
WorkContractGroup implements a work dispatcher capable of managing thousands of tasks without locks or blocking operations. It provides a comprehensive pool of work contracts with allocation, scheduling, and execution primitives suitable for job systems, task graphs, and high-throughput work management scenarios.
The implementation uses SignalTree-based lock-free operations, enabling multiple threads to schedule and select work concurrently without contention. This design is optimized for game engines, parallel processing systems, and applications requiring management of numerous small work units.
Key features:
- Lock-free contract scheduling and selection
- Generation-based handles prevent use-after-free bugs
- Immediate resource cleanup on completion
- Statistical monitoring (active/scheduled counts)
- Wait functionality for synchronization points
Important: This class provides scheduling primitives without handling parallel execution directly. External executors such as WorkService are required for concurrent work processing. The class functions as a centralized work registry where tasks are posted and claimed by worker threads.
Handle semantics:
- WorkContractHandle derives from EntropyObject and is stamped with (owner + index + generation)
- Copying a handle copies the stamped identity; validation is performed against this group’s slots
- The group owns the lifetime; when a slot is released, the object’s identity is cleared and the generation is incremented to invalidate stale handles
// Complete workflow: mixed execution with worker serviceWorkContractGroup group(1024);WorkService service(4); // 4 worker threadsservice.addWorkContractGroup(&group);service.start();
// Submit background workstd::vector<WorkContractHandle> handles;for (int i = 0; i < 10; ++i) { auto handle = group.createContract([i]() { processData(i); }); handle.schedule(); handles.push_back(handle);}
// Submit main thread workauto uiHandle = group.createContract([]() { updateProgressBar();}, ExecutionType::MainThread);uiHandle.schedule();
// Main thread pumps its workwhile (group.hasMainThreadWork()) { group.executeMainThreadWork(5); // Process up to 5 per frame renderFrame();}
// Wait for all background work to completegroup.wait();service.stop();Public Types Documentation
Section titled “Public Types Documentation”using CapacityCallback
Section titled “using CapacityCallback”using EntropyEngine::Core::Concurrency::WorkContractGroup::CapacityCallback = std::list<std::function<void()>>::iterator;Public Functions Documentation
Section titled “Public Functions Documentation”function ~WorkContractGroup
Section titled “function ~WorkContractGroup”~WorkContractGroup()Destructor ensures all work is stopped and completed.
Follows a strict destruction protocol to prevent deadlocks:
- Calls stop() to prevent new work selection
- Calls wait() to ensure all executing work completes
- Unschedules and releases all remaining contracts
- Reads concurrency provider pointer WITHOUT holding mutex lock
- Calls notifyGroupDestroyed() to inform provider of destruction
CRITICAL: The provider notification is made without holding the group’s concurrency provider mutex to prevent ABBA deadlock with WorkService. Any deviation from this protocol may result in deadlock during destruction.
The provider will then:
- Remove this group from its internal lists
- Call setConcurrencyProvider(nullptr) to clear the back-reference
This ensures proper bidirectional cleanup without lock ordering issues.
function wait
Section titled “function wait”void wait()Waits for all scheduled and executing contracts to complete.
Blocks until all work finishes. Includes scheduled and executing contracts.
// Submit a batch of workfor (int i = 0; i < 100; ++i) { auto handle = group.createContract([i]() { processItem(i); }); handle.schedule();}
// Wait for all work to completegroup.wait();std::cout << "All work finished!\n";function unscheduleContract
Section titled “function unscheduleContract”ScheduleResult unscheduleContract( const WorkContractHandle & handle)Removes a contract from scheduling (called by handle.unschedule()).
Parameters:
- handle Handle to the contract to unschedule
Return: Result indicating success or failure reason
Removes from ready list if not yet executing. Use handle method instead.
function toString
Section titled “function toString”virtual std::string toString() const overrideHuman-readable short string (class@ptr by default).
Reimplements: EntropyEngine::Core::EntropyObject::toString
function stop
Section titled “function stop”void stop()Stops the group from accepting new work selections.
Prevents new work selection. Executing work continues. Thread-safe.
function setTimedDeferralCallback
Section titled “function setTimedDeferralCallback”void setTimedDeferralCallback( std::function< size_t()> callback)Sets a callback for checking timed deferrals.
Parameters:
- callback Function that checks and schedules timed deferrals, or nullptr to clear
Allows external owners (like WorkGraph) to provide timer functionality without requiring inheritance or RTTI/dynamic_cast. Thread-safe: Protected by mutex.
function setConcurrencyProvider
Section titled “function setConcurrencyProvider”void setConcurrencyProvider( IConcurrencyProvider * provider)Associates this group with a concurrency provider.
Parameters:
- provider The concurrency provider to associate with, or nullptr to clear
Provider will be notified when work becomes available. Call during setup/teardown, not during active work execution.
function selectForMainThreadExecution
Section titled “function selectForMainThreadExecution”WorkContractHandle selectForMainThreadExecution( std::optional< std::reference_wrapper< uint64_t > > bias =std::nullopt)Selects a main thread scheduled contract for execution.
Parameters:
- bias Optional selection bias for fair work distribution
Return: Handle to an executing contract, or invalid handle if none available
Use this from your main thread to pick up work that must run there. Typically called in a loop until no more work is available. Thread-safe with other selections.
// Main thread pump patternuint64_t bias = 0;while (auto handle = group.selectForMainThreadExecution(std::ref(bias))) { group.executeContract(handle); group.completeMainThreadExecution(handle);}function selectForExecution
Section titled “function selectForExecution”WorkContractHandle selectForExecution( std::optional< std::reference_wrapper< uint64_t > > bias =std::nullopt)Selects a scheduled contract for execution.
Parameters:
- bias Optional selection bias for fair work distribution
Return: Handle to an executing contract, or invalid handle if none available
Atomically transitions a contract from Scheduled to Executing state.
function scheduledCount
Section titled “function scheduledCount”inline size_t scheduledCount() constGets the number of contracts currently scheduled for execution.
Return: Number of contracts currently scheduled and waiting for execution
if (group.scheduledCount() > 100) { std::cout << "Work load is getting full - might want to throttle\n";}function scheduleContract
Section titled “function scheduleContract”ScheduleResult scheduleContract( const WorkContractHandle & handle)Schedules a contract for execution (called by handle.schedule()).
Parameters:
- handle Handle to the contract to schedule
Return: Result indicating success or failure reason
Transitions a contract from Allocated to Scheduled state. Use the handle method instead of calling this directly.
function resume
Section titled “function resume”void resume()Resumes the group to allow new work selections.
Clears the stopping flag to allow selectForExecution() to return work again. Does NOT automatically notify waiting threads.
Thread-safe.
function removeOnCapacityAvailable
Section titled “function removeOnCapacityAvailable”void removeOnCapacityAvailable( CapacityCallback it)Remove a capacity available callback.
Parameters:
- it Iterator returned from addOnCapacityAvailable
function releaseContract
Section titled “function releaseContract”void releaseContract( const WorkContractHandle & handle)Immediately releases a contract (called by handle.release()).
Parameters:
- handle Handle to the contract to release
Forcibly frees a contract. Use the handle method instead.
function operator=
Section titled “function operator=”WorkContractGroup & operator=( const WorkContractGroup &) =deletefunction operator=
Section titled “function operator=”WorkContractGroup & operator=( WorkContractGroup && other)function mainThreadScheduledCount
Section titled “function mainThreadScheduledCount”inline size_t mainThreadScheduledCount() constGets the number of main thread contracts currently scheduled.
Return: Number of main thread contracts waiting for execution
function mainThreadExecutingCount
Section titled “function mainThreadExecutingCount”inline size_t mainThreadExecutingCount() constGets the number of main thread contracts currently executing.
Return: Number of main thread contracts being executed
function isValidHandle
Section titled “function isValidHandle”bool isValidHandle( const WorkContractHandle & handle) constValidates a handle belongs to this group (called by handle.valid()).
Parameters:
- handle Handle to validate
Return: true if handle is valid and belongs to this group
Checks handle validity and generation. Use handle method instead.
function isStopping
Section titled “function isStopping”inline bool isStopping() constChecks if the group is in the process of stopping.
Return: true if stop() has been called, false otherwise
function hasMainThreadWork
Section titled “function hasMainThreadWork”inline bool hasMainThreadWork() constChecks if there are any main thread contracts ready to execute.
Return: true if main thread work is available
function getContractState
Section titled “function getContractState”ContractState getContractState( const WorkContractHandle & handle) constGets the current state of a contract.
Parameters:
- handle Handle to query
Return: Current state of the contract, or Free if handle is invalid
function getConcurrencyProvider
Section titled “function getConcurrencyProvider”inline IConcurrencyProvider * getConcurrencyProvider() constGets the currently associated concurrency provider.
Return: The current provider, or nullptr if none is set
function executingCount
Section titled “function executingCount”size_t executingCount() constReturns the current number of contracts being actively executed.
Return: The number of currently executing contracts
Useful for thread scheduling and load balancing decisions.
function executeMainThreadWork
Section titled “function executeMainThreadWork”size_t executeMainThreadWork( size_t maxContracts)Executes main thread targeted work contracts with a limit.
Parameters:
- maxContracts Maximum number of contracts to execute
Return: Number of contracts actually executed
Use when you need to bound main thread work per frame/iteration. Prevents blocking the main thread for too long. Must be called from the main thread.
// Limit main thread work to maintain 60 FPSvoid gameLoop() { // Execute at most 5 tasks per frame size_t executed = group.executeMainThreadWork(5); renderFrame();}function executeContract
Section titled “function executeContract”void executeContract( const WorkContractHandle & handle)Executes the work function of a contract.
Parameters:
- handle Handle to the contract to execute (must be in Executing state)
Only call on contracts returned by selectForExecution().
function executeAllMainThreadWork
Section titled “function executeAllMainThreadWork”size_t executeAllMainThreadWork()Executes all main thread targeted work contracts.
Return: Number of contracts actually executed
Convenience method that handles the full pump cycle internally. Use this when you want to drain all main thread work at once. Must be called from the main thread.
// In your game loop or UI threadvoid updateMainThread() { size_t executed = group.executeAllMainThreadWork(); if (executed > 0) { LOG_DEBUG("Processed {} main thread tasks", executed); }}function executeAllBackgroundWork
Section titled “function executeAllBackgroundWork”void executeAllBackgroundWork()Executes all background (non-main-thread) contracts sequentially in the calling thread.
Grabs every scheduled background contract and executes them one by one in the current thread. Uses bias rotation to prevent starvation. Does NOT execute main thread targeted contracts.
// Schedule several background tasksfor (int i = 0; i < 10; ++i) { auto handle = group.createContract([i]() { std::cout << "Task " << i << "\n"; }); // Default is ExecutionType::AnyThread handle.schedule();}
// Execute all background contractsgroup.executeAllBackgroundWork();// All background tasks are now completefunction description
Section titled “function description”virtual std::string description() const overrideLong-form description; defaults to toString().
Reimplements: EntropyEngine::Core::EntropyObject::description
function debugString
Section titled “function debugString”virtual std::string debugString() const overrideDebug-oriented string including refcount and handle when present.
Reimplements: EntropyEngine::Core::EntropyObject::debugString
function createContract
Section titled “function createContract”WorkContractHandle createContract( std::function< void()> work, ExecutionType executionType =ExecutionType::AnyThread)Creates a new work contract with the given work function.
Parameters:
- work Function to execute when contract runs (should be thread-safe)
- executionType Where this contract should be executed (default: AnyThread)
Return: Handle to the created contract, or invalid handle if group is full
// Simple work for any threadauto handle = group.createContract([]() { std::cout << "Hello from work thread!\n";});
// Main thread targeted workauto mainHandle = group.createContract([]() { updateUI();}, ExecutionType::MainThread);
// Check if creation succeededif (!handle.valid()) { std::cerr << "Group is full - can't create more work\n";}function completeMainThreadExecution
Section titled “function completeMainThreadExecution”void completeMainThreadExecution( const WorkContractHandle & handle)Completes execution and cleans up a main thread contract.
Parameters:
- handle Handle to the main thread contract that finished executing
Like completeExecution() but for main thread contracts. Updates the correct counters and frees the contract for reuse. Always call this after executeContract() for main thread work.
auto handle = group.selectForMainThreadExecution();if (handle.valid()) { group.executeContract(handle); group.completeMainThreadExecution(handle); // Essential cleanup}function completeExecution
Section titled “function completeExecution”void completeExecution( const WorkContractHandle & handle)Completes execution and cleans up a contract.
Parameters:
- handle Handle to the contract that finished executing
Must be called after executeContract() to complete the lifecycle.
function className
Section titled “function className”inline virtual const char * className() const overrideRuntime class name for diagnostics and reflection.
Reimplements: EntropyEngine::Core::EntropyObject::className
function classHash
Section titled “function classHash”virtual uint64_t classHash() const overrideStable type hash for cross-language identification.
Reimplements: EntropyEngine::Core::EntropyObject::classHash
function checkTimedDeferrals
Section titled “function checkTimedDeferrals”size_t checkTimedDeferrals()Checks for timed deferrals and schedules ready nodes.
Return: Number of nodes that were scheduled from timed deferral queue
Invokes the timed deferral callback if one is set (used by WorkGraph for timer support). Returns 0 if no callback is registered (standard WorkContractGroups don’t support timers). Thread-safe: Protected by mutex.
function capacity
Section titled “function capacity”inline size_t capacity() constGets the maximum capacity of this group.
Return: Maximum number of contracts this group can handle
function addOnCapacityAvailable
Section titled “function addOnCapacityAvailable”CapacityCallback addOnCapacityAvailable( std::function< void()> callback)Add a callback to be invoked when capacity becomes available.
Parameters:
- callback Function to call when capacity is available
Return: Iterator that can be used to remove the callback
Called after a contract completes and frees up capacity.
function activeCount
Section titled “function activeCount”inline size_t activeCount() constGets the number of currently allocated contracts.
Return: Number of contracts that have been created but not yet released
std::cout << "Using " << group.activeCount() << " of " << group.capacity() << " available slots\n";function abortExecution
Section titled “function abortExecution”void abortExecution( const WorkContractHandle & handle)Aborts execution without running the task (shutdown-only path).
function WorkContractGroup
Section titled “function WorkContractGroup”explicit WorkContractGroup( size_t capacity, std::string name ="WorkContractGroup")Constructs a work contract group with specified capacity.
Parameters:
- capacity Maximum number of contracts (typically 1024-8192)
Pre-allocates all data structures for lock-free operation. Choose capacity based on peak concurrent load.
// For a game engine handling frame tasksWorkContractGroup frameWork(2048);
// For background processingWorkContractGroup backgroundTasks(512);function WorkContractGroup
Section titled “function WorkContractGroup”WorkContractGroup( const WorkContractGroup &) =deletefunction WorkContractGroup
Section titled “function WorkContractGroup”WorkContractGroup( WorkContractGroup && other)Updated on 2026-01-26 at 16:50:32 -0500