Skip to content

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.

PowerPool State Machines

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

PoolState

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

CanCreateNewWorker

Trigger Event State Change If CAS Fails Prerequisite
When preparing to create a thread NotAllowed (CAS) Directly skip
When thread creation is completed Allowed

CanDeleteRedundantWorker

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

Worker State Machines

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

WorkerState

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

CanDispose

Trigger Event State Change If CAS Fails Prerequisite
On Dispose NotAllowed (CAS) Directly skip

CanForceStop

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

CanGetWork

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

WorkStealability

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

WorkHeldState

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

Clone this wiki locally