1+ //! A generic, priority-aware, work-stealing queue implementation.
2+ //!
3+ //! This module is self-contained and can be used by any scheduler or
4+ //! application to manage and distribute tasks of any type that can be
5+ //! prioritized.
6+
17#![ allow( non_snake_case, non_camel_case_types) ]
28
39use std:: sync:: Arc ;
410
511use crossbeam_deque:: { Injector , Stealer , Worker } ;
612use rand:: seq:: SliceRandom ;
713
14+ /// Defines a contract for types that can be prioritized by the queue.
815pub trait Prioritized {
9- type P : PartialEq + Eq + Copy ;
10-
11- fn GetPriority ( & self ) -> Self :: P ;
16+ /// The type of the priority value used by the implementor.
17+ type Kind : PartialEq + Eq + Copy ;
18+ /// A method to retrieve the priority of the item.
19+ fn Rank ( & self ) -> Self :: Kind ;
1220}
1321
22+ /// Defines the internal priority levels used by the generic queue.
1423#[ derive( Debug , Clone , Copy , PartialEq , Eq ) ]
1524pub enum Priority {
1625 High ,
17-
1826 Normal ,
19-
2027 Low ,
2128}
2229
30+ /// Holds the queue components that are safe to share across all threads.
31+ ///
32+ /// This includes global injectors for submitting new tasks and stealers for
33+ /// taking tasks from other workers, organized by priority level.
2334struct Share < T > {
35+ /// Global, multi-producer queues for each priority.
2436 Injector : ( Injector < T > , Injector < T > , Injector < T > ) ,
25-
37+ /// Share handles for stealing tasks from each worker's queue.
2638 Stealer : ( Vec < Stealer < T > > , Vec < Stealer < T > > , Vec < Stealer < T > > ) ,
2739}
2840
29- pub struct StealingQueue < T : Prioritized < P = Priority > > {
41+ /// A generic, priority-aware, work-stealing queue.
42+ ///
43+ /// This is the public-facing entry point for submitting tasks. It is generic
44+ /// over any task type `T` that implements the `Prioritized` trait.
45+ pub struct StealingQueue < T : Prioritized < Kind = Priority > > {
46+ /// A shared, thread-safe pointer to the queue's shared components.
3047 Share : Arc < Share < T > > ,
3148}
3249
50+ /// Contains all necessary components for a single worker thread to operate.
51+ ///
52+ /// This includes the thread-local `Worker` deques, which are not safe to share,
53+ /// making this context object the sole owner of a worker's private queues.
3354pub struct Context < T > {
55+ /// A unique identifier for the worker, used to avoid self-stealing.
3456 pub Identifier : usize ,
35-
57+ /// Thread-local work queues for each priority level.
3658 Local : ( Worker < T > , Worker < T > , Worker < T > ) ,
37-
59+ /// A reference to the shared components of the entire queue system.
3860 Share : Arc < Share < T > > ,
3961}
4062
41- impl < T : Prioritized < P = Priority > > StealingQueue < T > {
42- pub fn New ( Count : usize ) -> ( Self , Vec < Context < T > > ) {
63+ impl < T : Prioritized < Kind = Priority > > StealingQueue < T > {
64+ /// Creates a complete work-stealing queue system.
65+ ///
66+ /// This function initializes all the necessary queues, both shared and
67+ /// thread-local, for a given number of workers.
68+ ///
69+ /// Returns a tuple containing:
70+ /// 1. The public-facing `StealingQueue` for submitting new tasks.
71+ /// 2. A `Vec` of `Context` objects, one for each worker thread to own.
72+ pub fn Create ( Count : usize ) -> ( Self , Vec < Context < T > > ) {
4373 let mut High : Vec < Worker < T > > = Vec :: with_capacity ( Count ) ;
44-
4574 let mut Normal : Vec < Worker < T > > = Vec :: with_capacity ( Count ) ;
46-
4775 let mut Low : Vec < Worker < T > > = Vec :: with_capacity ( Count ) ;
4876
77+ // For each priority level, create a thread-local worker queue and its
78+ // corresponding shared stealer.
4979 let StealerHigh : Vec < Stealer < T > > = ( 0 ..Count )
5080 . map ( |_| {
5181 let Worker = Worker :: new_fifo ( ) ;
52-
5382 let Stealer = Worker . stealer ( ) ;
54-
5583 High . push ( Worker ) ;
56-
5784 Stealer
5885 } )
5986 . collect ( ) ;
6087
6188 let StealerNormal : Vec < Stealer < T > > = ( 0 ..Count )
6289 . map ( |_| {
6390 let Worker = Worker :: new_fifo ( ) ;
64-
6591 let Stealer = Worker . stealer ( ) ;
66-
6792 Normal . push ( Worker ) ;
68-
6993 Stealer
7094 } )
7195 . collect ( ) ;
7296
7397 let StealerLow : Vec < Stealer < T > > = ( 0 ..Count )
7498 . map ( |_| {
7599 let Worker = Worker :: new_fifo ( ) ;
76-
77100 let Stealer = Worker . stealer ( ) ;
78-
79101 Low . push ( Worker ) ;
80-
81102 Stealer
82103 } )
83104 . collect ( ) ;
84105
85- let Shared = Arc :: new ( Share {
106+ // Bundle all shared components into an Arc for safe sharing.
107+ let Share = Arc :: new ( Share {
86108 Injector : ( Injector :: new ( ) , Injector :: new ( ) , Injector :: new ( ) ) ,
87-
88109 Stealer : ( StealerHigh , StealerNormal , StealerLow ) ,
89110 } ) ;
90111
91- let mut Context = Vec :: with_capacity ( Count ) ;
92-
93- for Id in 0 .. Count {
94- Context . push ( Context {
95- Identifier : Id ,
96-
112+ // Create a unique context for each worker, giving it ownership of its
113+ // local queues and a reference to the shared components.
114+ let mut Contexts = Vec :: with_capacity ( Count ) ;
115+ for Identifier in 0 .. Count {
116+ Contexts . push ( Context {
117+ Identifier ,
97118 Local : ( High . remove ( 0 ) , Normal . remove ( 0 ) , Low . remove ( 0 ) ) ,
98-
99- Share : Shared . clone ( ) ,
119+ Share : Share . clone ( ) ,
100120 } ) ;
101121 }
102122
103- let Queue = Self { Share : Shared } ;
104-
105- ( Queue , Context )
123+ let Queue = Self { Share } ;
124+ ( Queue , Contexts )
106125 }
107126
127+ /// Submits a new task to the appropriate global queue based on its
128+ /// priority. This method is thread-safe and can be called from any
129+ /// context.
108130 pub fn Submit ( & self , Task : T ) {
109- match Task . GetPriority ( ) {
131+ match Task . Rank ( ) {
110132 Priority :: High => self . Share . Injector . 0 . push ( Task ) ,
111-
112133 Priority :: Normal => self . Share . Injector . 1 . push ( Task ) ,
113-
114134 Priority :: Low => self . Share . Injector . 2 . push ( Task ) ,
115135 }
116136 }
117137}
118138
119139impl < T > Context < T > {
120- pub fn NextTask ( & self ) -> Option < T > {
140+ /// Finds the next available task for the worker to execute.
141+ // This method implements the complete work-finding logic:
142+ /// 1. Check local queue (high to low priority).
143+ /// 2. Steal from the system (high to low priority).
144+ pub fn Next ( & self ) -> Option < T > {
121145 self . Local
122146 . 0
123147 . pop ( )
@@ -128,25 +152,27 @@ impl<T> Context<T> {
128152 . or_else ( || self . Steal ( & self . Share . Injector . 2 , & self . Share . Stealer . 2 , & self . Local . 2 ) )
129153 }
130154
131- fn Steal < ' a > ( & self , Injector : & ' a Injector < T > , Stealer : & ' a [ Stealer < T > ] , Local : & ' a Worker < T > ) -> Option < T > {
155+ /// Attempts to steal a task from a specific priority set.
156+ ///
157+ /// It first tries to steal a batch from the global injector queue. If that
158+ /// fails, it attempts to steal from a randomly chosen peer worker to ensure
159+ /// fair distribution and avoid contention hotspots.
160+ fn Steal < ' a > ( & self , Injector : & ' a Injector < T > , Stealers : & ' a [ Stealer < T > ] , Local : & ' a Worker < T > ) -> Option < T > {
132161 if Injector . steal_batch_and_pop ( Local ) . is_success ( ) {
133162 return Local . pop ( ) ;
134163 }
135164
136- let mut Index : Vec < usize > = ( 0 ..Stealer . len ( ) ) . collect ( ) ;
165+ let mut Indices : Vec < usize > = ( 0 ..Stealers . len ( ) ) . collect ( ) ;
166+ Indices . shuffle ( & mut rand:: rng ( ) ) ;
137167
138- Index . shuffle ( & mut rand:: rng ( ) ) ;
139-
140- for i in Index {
141- if i == self . Identifier {
168+ for Index in Indices {
169+ if Index == self . Identifier {
142170 continue ;
143171 }
144-
145- if Stealer [ i] . steal_batch_and_pop ( Local ) . is_success ( ) {
172+ if Stealers [ Index ] . steal_batch_and_pop ( Local ) . is_success ( ) {
146173 return Local . pop ( ) ;
147174 }
148175 }
149-
150176 None
151177 }
152178}
0 commit comments