Priorities
Task priorities influence the order in which queued tasks are selected inside a worker's local queue.
Set a priority through TaskOptions:
vix::threadpool::TaskOptions options = vix::threadpool::TaskOptions::with_priority(
vix::threadpool::TaskPriority::high
);
auto future = pool.submit([](){
return 42;
}, options);Priority affects queued work. It does not create a global execution order across the entire thread pool.
TaskPriority
The module defines five priority levels:
enum class TaskPriority : std::int32_t
{
lowest = -2,
low = -1,
normal = 0,
high = 1,
highest = 2
};Their order is:
highest
↓
high
↓
normal
↓
low
↓
lowestA larger numeric value represents a higher priority.
Default priority
A default-constructed TaskOptions uses normal priority:
vix::threadpool::TaskOptions options;which gives:
priority = normalOrdinary submissions therefore use normal priority:
auto future = pool.submit([](){
return 42;
});unless the task options specify another value.
Set a priority
The convenience constructor is:
vix::threadpool::TaskOptions options = vix::threadpool::TaskOptions::with_priority(
vix::threadpool::TaskPriority::high
);The setter form is:
vix::threadpool::TaskOptions options;
options.set_priority(
vix::threadpool::TaskPriority::high
);Both can be passed to the normal submission APIs.
With submit():
auto future = pool.submit([](){
return 42;
}, options);With post():
const bool accepted = pool.post([](){
perform_work();
}, options);With handle():
auto handle = pool.handle([](){
return 42;
}, options);The same priority model applies to all of them.
Queue ordering
Each worker owns a local TaskQueue.
The queue orders tasks using two values:
1. TaskPriority
2. sequence numberHigher priority is considered first.
When two tasks have the same priority, the smaller sequence number comes first.
Conceptually:
highest, sequence 8
highest, sequence 12
high, sequence 4
normal, sequence 2
normal, sequence 7
low, sequence 1
lowest, sequence 3The next task selected from this queue is:
highest, sequence 8Higher priority runs first inside one queue
Suppose three tasks are waiting in the same worker queue:
Task A → low
Task B → highest
Task C → normalTheir execution order from that queue is:
Task B
↓
Task C
↓
Task AThe queue comparator first compares priority values:
highest = 2
normal = 0
low = -1so the highest-priority queued task is selected first.
Equal priorities preserve FIFO order
Every task receives a monotonically increasing sequence number when submitted through ThreadPool.
For three normal-priority tasks:
Task A → sequence 10
Task B → sequence 11
Task C → sequence 12their queue order is:
Task A
↓
Task B
↓
Task CPriority therefore does not destroy submission order when tasks have the same priority and are placed in the same worker queue.
The queue comparator is conceptually:
different priority?
│
├── yes → higher priority first
│
└── no → smaller sequence firstPriority is local to a worker
ThreadPool workers do not share one global task queue.
For example:
Worker 1
└── high task
Worker 2
└── normal taskboth workers can execute simultaneously.
The normal-priority task on Worker 2 does not wait for the high-priority task on Worker 1 merely because its priority is lower.
Priority therefore answers:
Which queued task should this worker take next?It does not answer:
Which task across the entire pool must execute next?Priority does not select the worker
Scheduling and priority happen at different stages.
task submitted
↓
Scheduler chooses worker
↓
task enters worker queue
↓
priority orders local queue
↓
worker executes taskWorker selection is handled by the scheduler.
Priority is evaluated after the destination worker has been selected.
For example:
vix::threadpool::TaskOptions options = vix::threadpool::TaskOptions::with_priority(
vix::threadpool::TaskPriority::highest
);
auto future = pool.submit([](){
return 42;
}, options);does not mean:
select the least busy worker because priority is highestThe normal scheduling policy still selects the worker according to affinity or queue load.
The priority then determines the task's position inside that worker's queue.
See Scheduling Model.
Priority does not preempt a running task
Priority affects queued tasks.
It does not interrupt work that is already executing.
Consider one worker:
Worker
│
├── currently running: normal task
│
└── queue:
highest taskThe highest-priority task cannot interrupt the normal task.
The worker first finishes the currently executing callable.
Then it selects the highest-priority queued task.
Conceptually:
normal task already running
↓
highest task arrives
↓
normal task continues
↓
normal task finishes
↓
highest task startsThis is non-preemptive task execution.
Priority does not guarantee immediate execution
A highest-priority task can still wait.
For example:
Worker 1
running: long task
queue:
highest taskThe highest-priority task remains queued until the worker finishes its current task.
Priority only changes its position relative to other queued work.
It cannot make an unavailable worker immediately available.
Priority and multiple workers
Consider a two-worker pool.
Worker 1
running: normal A
queue:
highest B
Worker 2
running: low C
queue:
normal DTasks A and C are already running.
Neither B nor D can preempt them.
After Worker 1 finishes A, it selects B.
After Worker 2 finishes C, it selects D.
The global execution sequence can therefore look like:
A and C running concurrently
Worker 2 finishes C
↓
D starts
Worker 1 finishes A
↓
B startsEven though B has the highest priority, D can begin earlier because it belongs to another worker queue.
This is why priority must not be treated as a global ordering guarantee.
Priority and worker affinity
Affinity determines where a task is placed.
Priority determines where it appears inside that selected worker's queue.
For example:
vix::threadpool::TaskOptions options;
options
.set_affinity(vix::threadpool::WorkerId{2})
.set_priority(vix::threadpool::TaskPriority::highest);
auto future = pool.submit([](){
return 42;
}, options);Conceptually:
affinity
↓
select Worker 2
↓
priority
↓
place task according to
Worker 2 queue orderingThe two controls are complementary.
See Worker Affinity.
Priority and queue capacity
Priority does not bypass queue capacity.
If a bounded worker queue is full, a highest-priority task does not automatically remove a lower-priority task.
For example:
Worker queue capacity = 2
queue:
low
normal
new task:
highestIf the queue is already full, the new task can be rejected.
The queue does not evict:
lowto make room for:
highestPriority controls ordering among accepted queued tasks.
Queue admission is a separate operation.
See Queue and Rejection Policies.
Priority values
The numeric priority values are stable:
| Priority | Value |
|---|---|
lowest | -2 |
low | -1 |
normal | 0 |
high | 1 |
highest | 2 |
Convert a priority to its numeric value with:
const std::int32_t value = vix::threadpool::to_priority_value(
vix::threadpool::TaskPriority::high
);The result is:
1These values are primarily useful for comparison and diagnostics.
Application code should normally use the named enum values.
Compare priorities
The module provides:
vix::threadpool::priority_higher_than(
lhs,
rhs
);For example:
const bool result = vix::threadpool::priority_higher_than(
vix::threadpool::TaskPriority::high,
vix::threadpool::TaskPriority::normal
);The result is:
trueThe comparison is equivalent to comparing the numeric priority values.
For example:
high = 1
normal = 0
1 > 0
↓
trueEqual priorities are not considered higher than each other.
const bool result = vix::threadpool::priority_higher_than(
vix::threadpool::TaskPriority::normal,
vix::threadpool::TaskPriority::normal
);returns:
falseReadable priority names
Use to_string() when a readable priority name is needed:
const char* name = vix::threadpool::to_string(
vix::threadpool::TaskPriority::highest
);The result is:
highestThe available names are:
lowest
low
normal
high
highestAn unknown enum value returns:
unknownDefault priority in ThreadPoolConfig
ThreadPoolConfig exposes:
config.default_priority;and its default value is:
vix::threadpool::TaskPriority::normalHowever, the current ThreadPool submission path does not merge config.default_priority into submitted TaskOptions.
For example:
vix::threadpool::ThreadPoolConfig config;
config.default_priority = vix::threadpool::TaskPriority::high;
vix::threadpool::ThreadPool pool(config);should not currently be used to make ordinary submissions high priority.
Set the priority explicitly on the task:
vix::threadpool::TaskOptions options = vix::threadpool::TaskOptions::with_priority(
vix::threadpool::TaskPriority::high
);
auto future = pool.submit([](){
return 42;
}, options);See Configuration.
Priorities in higher-level operations
Higher-level parallel operations can propagate task options to the work they submit.
For example, their configuration can carry a high task priority so that the generated worker tasks enter local queues with that priority.
The underlying behavior remains the same:
parallel operation
↓
create several tasks
↓
TaskOptions contain priority
↓
tasks reach worker queues
↓
normal priority ordering appliesParallel algorithms do not create a separate priority system.
See Parallel Algorithms.
When to use priority
Priority is useful when queued work has different urgency but can still share the same worker runtime.
For example:
highest
urgent work that should lead a local queue
high
work that should usually precede ordinary queued work
normal
regular application work
low
work that can wait behind normal work
lowest
least urgent queued workThese categories express relative queue preference.
They should not be interpreted as real-time scheduling guarantees.
Do not use priority for dependencies
Suppose Task B requires Task A to finish first.
This is not sufficient:
Task A → high
Task B → lowThe scheduler may place them on different workers, so B can execute concurrently with or before A.
Priority is not a dependency mechanism.
When work has an actual dependency, express it through synchronization, results, scopes, or explicit control flow.
For example:
auto first = pool.submit([](){
return produce_value();
});
const auto value = first.get();
auto second = pool.submit([value](){
return consume_value(value);
});The dependency is explicit and does not rely on scheduler timing.
Do not use priority as a timing guarantee
A priority level does not mean:
highest → execute immediately
high → execute within N milliseconds
low → execute after all global workThe actual start time depends on:
selected worker
currently running work
local queue contents
queue capacity
other concurrent activityPriority provides relative local queue ordering only.
Priority model summary
The complete priority path is:
TaskOptions
↓
TaskPriority
↓
task submitted
↓
Scheduler selects worker
↓
task enters local TaskQueue
↓
higher priority first
↓
equal priority?
↓
smaller sequence first
↓
worker executes taskThe important properties are:
- The levels are
lowest,low,normal,high, andhighest. normalis the default task priority.- Higher numeric values represent higher priority.
- Priority is evaluated inside each worker's local queue.
- Equal-priority tasks use their sequence number for FIFO ordering.
- Priority does not select the worker.
- Priority does not create a global ordering across workers.
- Priority does not preempt a running task.
- Priority does not bypass queue capacity.
- Priority does not express dependencies.
ThreadPoolConfig::default_priorityis not currently applied to ordinary submissions.
Continue with Worker Affinity for worker placement or Queue and Rejection Policies for queue admission behavior.