A lightweight asynchronous task scheduling library designed for high-performance applications and game engines.
Clockwork++ was primarily designed for game engines and applications that require fine-grained control over asynchronous work. Unlike traditional thread pool implementations, Clockwork++ supports multiple independent thread pools, allowing workloads to be separated by responsibility.
For example, dedicated pools can be created for:
- Networking / Socket operations
- File I/O
- Asset streaming
- Physics simulation
- General compute workloads
- Background maintenance tasks
Tasks can be dispatched to a specific pool and assigned a priority, ensuring critical work is processed ahead of lower-priority jobs.
- Multiple independent thread pools
- Task prioritization
- Awaitable task handles
- Simple async execution API
- Reusable dispatchers
- Recurring scheduled tasks
- Minimal dependencies
- Designed for engine and real-time application workloads
Before dispatching any work, a Clockwork context must be created.
using namespace Raidcore::Clockwork;
// Create N thread pools with automatic thread counts.
Context::Create(4);
// Or specify both pool count and threads per pool.
Context::Create(4, 2);
When shutting down:
```cpp
Context::Destroy();Use Run() to execute work asynchronously and receive an awaitable task handle.
auto task = Run<int>(
ETaskPriority::Normal,
[]()
{
return 42;
}
);
int result = task->Await();You can also dispatch directly to a specific pool:
auto task = Run<std::string>(
1,
ETaskPriority::High,
[]()
{
return "Hello Clockwork";
}
);
std::string value = task->Await();Clockwork++ supports prioritized execution:
| Priority | Purpose |
|---|---|
| Immediate | Time-sensitive engine work |
| High | Networking, gameplay systems |
| Normal | General application tasks |
| Low | Background processing |
Run<void>(
ETaskPriority::Immediate,
[]()
{
ProcessNetworkMessages();
}
);
Run<void>(
ETaskPriority::Low,
[]()
{
RebuildCache();
}
);A Dispatcher<T> stores a reusable asynchronous operation together with its target thread pool and priority.
Dispatcher<int> dispatcher(
[]()
{
return PerformExpensiveCalculation();
},
2, // Pool ID
ETaskPriority::High
);auto task = dispatcher.Dispatch();
int result = task->Await();Or call it directly:
auto task = dispatcher();dispatcher.SetPool(1);
dispatcher.SetPriority(ETaskPriority::Critical);
dispatcher.SetAction([]()
{
return GenerateData();
});Scheduled tasks allow you to run recurring work at fixed intervals using the Clockwork context.
They are ideal for:
- Engine tick systems
- Network polling
- Heartbeats
- Cleanup jobs
- Periodic background maintenance
static std::shared_ptr<ScheduledTask> Schedule(
uint32_t aPool,
std::chrono::milliseconds aInterval,
Action<void> aAction,
std::chrono::steady_clock::time_point aFirstExecution =
std::chrono::steady_clock::now()
);static std::shared_ptr<ScheduledTask> Schedule(
std::chrono::milliseconds aInterval,
Action<void> aAction,
std::chrono::steady_clock::time_point aFirstExecution =
std::chrono::steady_clock::now()
);The second overload defaults to pool 0.
auto task = Context::Schedule(
std::chrono::milliseconds(1000),
[]()
{
std::cout << "Running every second!" << std::endl;
}
);auto task = Context::Schedule(
1,
std::chrono::milliseconds(500),
[]()
{
PollNetworkState();
}
);auto task = Context::Schedule(
std::chrono::milliseconds(1000),
[]()
{
Heartbeat();
},
std::chrono::steady_clock::now() + std::chrono::milliseconds(2000)
);task->Cancel();Clockwork++ supports multiple isolated thread pools.
Context::Create(3, 4);Example layout:
| Pool | Purpose |
|---|---|
| 0 | General Tasks |
| 1 | Networking |
| 2 | Asset Streaming |
Tasks are routed to the appropriate pool at dispatch time.
Each thread pool owns a set of worker threads managed automatically by the context.
Context::Create(2, 4);This creates:
- Pool 0 → 4 threads
- Pool 1 → 4 threads
Total: 8 worker threads.
Workers continuously process queued tasks by priority until the context is destroyed.
using namespace Raidcore::Clockwork;
int main()
{
Context::Create(2, 4);
auto task = Run<int>(
0,
ETaskPriority::Normal,
[]()
{
return 123;
}
);
auto scheduled = Context::Schedule(
std::chrono::milliseconds(1000),
[]()
{
Tick();
}
);
int value = task->Await();
Context::Destroy();
return 0;
}Developed by Kevin Bieniek as part of the Nexus Engine project for Raidcore.
Inspiration for the library was drawn from ArenaNet's Arch Engine and the general implementation of async in C#.
Clockwork++ is licensed under the MIT license. See LICENSE for details.