History

GSF.Core: Updated LogicalThread API to handle prioritization at the thread scheduler so that threads can be reprioritized based on the priority of their tasks.

StephenCWills committed 9 years ago

Commit d6482bb1 parent 3c892cb4 files · +153 −53Browse files

Showing the changes to Source/Libraries/GSF.Core.Shared/Threading/LogicalThread.cs (1 of 4 files). Show all

Unified · Split

Source/Libraries/GSF.Core.Shared/Threading/LogicalThread.cs+65−26
@@ -158,7 +158,8 @@ namespace GSF.Threading · 157 unmodified lines
158158 private LogicalThreadScheduler m_scheduler;
159159 private ConcurrentQueue<Action>[] m_queues;
160160 private Dictionary<object, object> m_threadLocalStorage;
161− private int m_isActive;
161+ private ICancellationToken m_nextExecutionToken;
162+ private int m_activePriority;
162163
163164 private LogicalThreadStatistics m_statistics;
164165
@@ -170,16 +171,7 @@ namespace GSF.Threading · 5 unmodified lines
170171 /// Creates a new instance of the <see cref="LogicalThread"/> class.
171172 /// </summary>
172173 public LogicalThread()
173− : this(1)
174− {
175− }
176−
177− /// <summary>
178− /// Creates a new instance of the <see cref="LogicalThread"/> class.
179− /// </summary>
180− /// <param name="priorityLevels">The number of levels of priority supported by this logical thread.</param>
181− public LogicalThread(int priorityLevels)
182− : this(DefaultScheduler, priorityLevels)
174+ : this(DefaultScheduler)
183175 {
184176 }
185177
@@ -187,20 +179,16 @@ namespace GSF.Threading · 1 unmodified line
187179 /// Creates a new instance of the <see cref="LogicalThread"/> class.
188180 /// </summary>
189181 /// <param name="scheduler">The <see cref="LogicalThreadScheduler"/> that created this thread.</param>
190− /// <param name="priorityLevels">The number of levels of priority supported by this logical thread.</param>
191182 /// <exception cref="ArgumentNullException"><paramref name="scheduler"/> is null.</exception>
192− /// <exception cref="ArgumentException"><paramref name="priorityLevels"/> is less than or equal to zero.</exception>
193− internal LogicalThread(LogicalThreadScheduler scheduler, int priorityLevels)
183+ internal LogicalThread(LogicalThreadScheduler scheduler)
194184 {
195185 if ((object)scheduler == null)
196186 throw new ArgumentNullException(nameof(scheduler));
197187
198− if (priorityLevels <= 0)
199− throw new ArgumentException($"A logical thread must have at least one priority level.", nameof(priorityLevels));
200−
201188 m_scheduler = scheduler;
202− m_queues = new ConcurrentQueue<Action>[priorityLevels];
189+ m_queues = new ConcurrentQueue<Action>[PriorityLevels];
203190 m_threadLocalStorage = new Dictionary<object, object>();
191+ m_nextExecutionToken = new CancellationToken();
204192 m_statistics = new LogicalThreadStatistics();
205193
206194 for (int i = 0; i < m_queues.Length; i++)
@@ -219,7 +207,7 @@ namespace GSF.Threading · 12 unmodified lines
219207 {
220208 get
221209 {
222− return m_queues.Length;
210+ return m_scheduler.PriorityLevels;
223211 }
224212 }
225213
@@ -235,6 +223,49 @@ namespace GSF.Threading · 9 unmodified lines
235223 }
236224 }
237225
226+ /// <summary>
227+ /// Gets or sets the priority at which the
228+ /// logical thread is queued by the scheduler.
229+ /// </summary>
230+ internal int ActivePriority
231+ {
232+ get
233+ {
234+ return Interlocked.CompareExchange(ref m_activePriority, 0, 0);
235+ }
236+ set
237+ {
238+ Interlocked.Exchange(ref m_activePriority, value);
239+ }
240+ }
241+
242+ /// <summary>
243+ /// Gets the priority of the next action to be processed on this logical thread.
244+ /// </summary>
245+ internal int NextPriority
246+ {
247+ get
248+ {
249+ return PriorityLevels - m_queues.TakeWhile(queue => queue.IsEmpty).Count();
250+ }
251+ }
252+
253+ /// <summary>
254+ /// Gets or sets the cancellation token for the next time
255+ /// the thread's actions will be executed by the scheduler.
256+ /// </summary>
257+ internal ICancellationToken NextExecutionToken
258+ {
259+ get
260+ {
261+ return Interlocked.CompareExchange(ref m_nextExecutionToken, null, null);
262+ }
263+ set
264+ {
265+ Interlocked.Exchange(ref m_nextExecutionToken, value);
266+ }
267+ }
268+
238269 #endregion
239270
240271 #region [ Methods ]
@@ -260,7 +291,7 @@ namespace GSF.Threading · 19 unmodified lines
260291 throw new ArgumentException($"Priority {priority} is outside the range between 1 and {PriorityLevels}.", nameof(priority));
261292
262293 m_queues[PriorityLevels - priority].Enqueue(action);
263− m_scheduler.SignalItemHandler(this);
294+ m_scheduler.SignalItemHandler(this, priority);
264295 }
265296
266297 /// <summary>
@@ -305,20 +336,28 @@ namespace GSF.Threading · 38 unmodified lines
305336 }
306337
307338 /// <summary>
308− /// Activates the thread if it is not already active.
339+ /// Attempts to activate the thread at the given priority.
309340 /// </summary>
310− /// <returns>True if this call to TryActivate caused the thread to be active.</returns>
311− internal bool TryActivate()
341+ /// <param name="priority">The priority at which to activate the thread.</param>
342+ /// <returns>True if the thread's priority needs to be changed to the given priority; false otherwise.</returns>
343+ internal bool TryActivate(int priority)
312344 {
313− return Interlocked.CompareExchange(ref m_isActive, 1, 0) == 0;
345+ // Always get the execution token before the
346+ // active priority to mitigate race conditions
347+ ICancellationToken nextExecutionToken = NextExecutionToken;
348+ int activePriority = ActivePriority;
349+ return (activePriority < priority) && nextExecutionToken.Cancel();
314350 }
315351
316352 /// <summary>
317− /// Deactivates the thread.
353+ /// Completely deactivates the thread, making it available for reactivation at any priority.
318354 /// </summary>
319355 internal void Deactivate()
320356 {
321− Interlocked.Exchange(ref m_isActive, 0);
357+ // Always update the active priority before the
358+ // execution token to mitigate race conditions
359+ ActivePriority = 0;
360+ NextExecutionToken = new CancellationToken();
322361 }
323362
324363 /// <summary>

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t