-
Notifications
You must be signed in to change notification settings - Fork 16
State Machine
ZjzMisaka edited this page Mar 25, 2026
·
4 revisions
PTP uses fine-grained atomic state machine transitions to avoid locks. This document helps developers understand how it works, in order to reduce development difficulty.
Most logic is optimistic concurrency control based on CAS: once CAS fails, it is directly skipped / recovered, while a small part uses spin-waiting. Logic that is spin-waited on must be instantaneous operations.
PTP state machines basically (in fact, all of them) only care about their final states, so the ABA problem does not need to be considered.
| State Machine | Description | Values |
|---|---|---|
| PoolState | Running state of the thread pool itself | NotRunning (Default), IdleChecked, Running |
| CanCreateNewWorker | Throttling when creating threads, to prevent creating too many threads under concurrency | Allowed (Default), NotAllowed |
| CanDeleteRedundantWorker | Throttling when threads need to be destroyed after exceeding limits, to prevent destroying unnecessary threads under concurrency | Allowed (Default), NotAllowed |
| Trigger Event | State Change | If CAS Fails | Prerequisite |
|---|---|---|---|
| When PoolIdled event and other cleanup work are completed | NotRunning | ||
| When it is detected during running that there is no running, waiting, or async task | IdleChecked (CAS) | Directly skip | |
| When attempting to enqueue a task while the current state is NotRunning | Running (CAS) | Directly skip |
| Trigger Event | State Change | If CAS Fails | Prerequisite |
|---|---|---|---|
| When preparing to create a thread | NotAllowed (CAS) | Directly skip | |
| When thread creation is completed | Allowed |
| Trigger Event | State Change | If CAS Fails | Prerequisite |
|---|---|---|---|
| When preparing to destroy a thread | NotAllowed (CAS) | Directly skip | |
| When thread destruction is completed | Allowed | ||
| When it is double-confirmed that the thread does not need to be destroyed | Allowed |
| State Machine | Description | Values |
|---|---|---|
| WorkerState | Running state of the Worker | Idle (Default), Running, ToBeDisposed |
| CanDispose | Used to prevent multiple Dispose calls | Allowed (Default), NotAllowed |
| CanForceStop | Used to prevent multiple ForceStop calls | Allowed (Default), NotAllowed |
| CanGetWork | Indicates whether this Worker can accept new work | Allowed, NotAllowed (Default), ToBeDisabled, Disabled |
| WorkStealability | Indicates whether this Worker can have its tasks stolen | Allowed (Default), NotAllowed |
| WorkHeldState | Indicates whether the current work is forcibly kept held | NotHeld (Default), Held |
| Trigger Event | State Change | If CAS Fails | Prerequisite |
|---|---|---|---|
| When a new task is enqueued | Running (CAS) | CAS is used to check the previous state; failure has no impact. If the state before CAS is Idle, initialize; otherwise just enqueue or put into DAC Inbox. | |
| When the thread needs to be naturally disposed | ToBeDisposed (CAS) | Restore CanGetWork state and skip | CanGetWork=Disabled |
| When the thread needs to be destroyed due to exceeding the thread count limit | ToBeDisposed | CanDeleteRedundantWorker=NotAllowed & CanGetWork=Disabled |
|
| When actually entering the Idle state | Idle | CanGetWork=ToBeDisabled | |
| When a temporary helper Worker is created | Running | ||
| When the temporary helper Worker finishes | Idle | ||
| When forced stop begins | ToBeDisposed |
| Trigger Event | State Change | If CAS Fails | Prerequisite |
|---|---|---|---|
| On Dispose | NotAllowed (CAS) | Directly skip |
| Trigger Event | State Change | If CAS Fails | Prerequisite |
|---|---|---|---|
| When preparing to force stop | NotAllowed (CAS) | Directly skip; if there is an associated return value, return the value representing force-stop failure | |
| When force stop is requested while WorkerState is already in a non-Running state | Allowed |
| Trigger Event | State Change | If CAS Fails | Prerequisite |
|---|---|---|---|
| When a Worker is newly created due to insufficient count | Allowed | ||
| When a Worker is attempted to be woken from Idle | NotAllowed (CAS) | Skip and put it back into the Idle set | |
| When a running Worker is attempted to be obtained to enqueue a new task | NotAllowed (CAS) | Directly skip | |
| When a Worker better suited for enqueuing the new task is found | Allowed | ||
| When being force-stopped | Disabled | ||
| When thread count exceeds the limit and the Worker is attempted to be destroyed | Disabled (CAS) | Directly skip | CanDeleteRedundantWorker=NotAllowed |
| When it is double-confirmed that the thread does not need to be destroyed | Allowed | ||
| When a new task has been successfully enqueued (excluding stealing) | Allowed | ||
| When attempting to enter Idle state | ToBeDisabled (CAS) | Directly skip | |
| When attempting to enter Idle state but a new task is obtained within this time window | Allowed (CAS) | CAS is only for verification during development | |
| When attempting to enter Idle state succeeds and there is no keep-alive setting | Disabled (CAS) | CAS is only for verification during development | |
| When attempting to enter Idle state succeeds, waiting to be woken up or destroyed after keep-alive timeout | Allowed (CAS) | CAS is only for verification during development | |
| When the thread needs to be naturally disposed | Disabled (CAS) | Use spinning; must exit spinning when it has succeeded or is already in Disabled state (failed but the state requirement is satisfied) | |
| When natural disposal of the thread fails (due to race; the current Worker has resumed running) | Allowed (CAS) | CAS is only for verification during development |
| Trigger Event | State Change | If CAS Fails | Prerequisite |
|---|---|---|---|
| When obtained in the help-execution logic in order to steal tasks | NotAllowed (CAS) | Directly skip | |
| When finishing stealing tasks in the help-execution logic | Allowed | ||
| When obtained in the work-stealing logic in order to steal tasks | NotAllowed (CAS) | Directly skip | |
| When, in the work-stealing logic, a Worker better suited for enqueuing new tasks is found | Allowed | ||
| When tasks are stolen from this Worker and the steal succeeds | Allowed | ||
| When the relationship between the Worker and its currently held work needs to be frozen (during force stop or cancellation) | NotAllowed (CAS) | Spin until the state changes. Both force stop and cancellation are non-blocking operations; freezing will always complete immediately, so the spinning will certainly be short-spin | |
| When the relationship between the Worker and its currently held work needs to be unfrozen | Allowed |
| Trigger Event | State Change | If CAS Fails | Prerequisite |
|---|---|---|---|
| When the relationship between the Worker and its currently held work needs to be frozen (during force stop or cancellation) | Held (CAS) | Spin until the state changes. Both force stop and cancellation are non-blocking operations; freezing will always complete immediately, so the spinning will certainly be short-spin | WorkStealability=NotAllowed |
| When the relationship between the Worker and its currently held work needs to be unfrozen | NotHeld |
- Sync | Async
- Pool Control | Work Control
- Divide And Conquer
- Thread Pool Sizing
- Work Callback | Default Callback
- Rejection Policy
- Parallel Execution
- Work Priority | Thread Priority
- Error Handling
- Work Timeout | Cumulative Work Timeout
- Work Dependency
- Work Group
- Events
- Runtime Status
- Running Timer
- Queue Type (FIFO | LIFO | Deque | Custom)
Core
Results
Options