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
158 private LogicalThreadScheduler m_scheduler;158 private LogicalThreadScheduler m_scheduler;
159 private ConcurrentQueue<Action>[] m_queues;159 private ConcurrentQueue<Action>[] m_queues;
160 private Dictionary<object, object> m_threadLocalStorage;160 private Dictionary<object, object> m_threadLocalStorage;
161 private int m_isActive;161 private ICancellationToken m_nextExecutionToken;
162 private int m_activePriority;
162 163
163 private LogicalThreadStatistics m_statistics;164 private LogicalThreadStatistics m_statistics;
164 165
@@ -170,16 +171,7 @@ namespace GSF.Threading · 5 unmodified lines
170 /// Creates a new instance of the <see cref="LogicalThread"/> class.171 /// Creates a new instance of the <see cref="LogicalThread"/> class.
171 /// </summary>172 /// </summary>
172 public LogicalThread()173 public LogicalThread()
173 : this(1)174 : this(DefaultScheduler)
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)
183 {175 {
184 }176 }
185 177
@@ -187,20 +179,16 @@ namespace GSF.Threading · 1 unmodified line
187 /// Creates a new instance of the <see cref="LogicalThread"/> class.179 /// Creates a new instance of the <see cref="LogicalThread"/> class.
188 /// </summary>180 /// </summary>
189 /// <param name="scheduler">The <see cref="LogicalThreadScheduler"/> that created this thread.</param>181 /// <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>
191 /// <exception cref="ArgumentNullException"><paramref name="scheduler"/> is null.</exception>182 /// <exception cref="ArgumentNullException"><paramref name="scheduler"/> is null.</exception>
192 /// <exception cref="ArgumentException"><paramref name="priorityLevels"/> is less than or equal to zero.</exception>183 internal LogicalThread(LogicalThreadScheduler scheduler)
193 internal LogicalThread(LogicalThreadScheduler scheduler, int priorityLevels)
194 {184 {
195 if ((object)scheduler == null)185 if ((object)scheduler == null)
196 throw new ArgumentNullException(nameof(scheduler));186 throw new ArgumentNullException(nameof(scheduler));
197 187
198 if (priorityLevels <= 0)
199 throw new ArgumentException($"A logical thread must have at least one priority level.", nameof(priorityLevels));
200
201 m_scheduler = scheduler;188 m_scheduler = scheduler;
202 m_queues = new ConcurrentQueue<Action>[priorityLevels];189 m_queues = new ConcurrentQueue<Action>[PriorityLevels];
203 m_threadLocalStorage = new Dictionary<object, object>();190 m_threadLocalStorage = new Dictionary<object, object>();
191 m_nextExecutionToken = new CancellationToken();
204 m_statistics = new LogicalThreadStatistics();192 m_statistics = new LogicalThreadStatistics();
205 193
206 for (int i = 0; i < m_queues.Length; i++)194 for (int i = 0; i < m_queues.Length; i++)
@@ -219,7 +207,7 @@ namespace GSF.Threading · 12 unmodified lines
219 {207 {
220 get208 get
221 {209 {
222 return m_queues.Length;210 return m_scheduler.PriorityLevels;
223 }211 }
224 }212 }
225 213
@@ -235,6 +223,49 @@ namespace GSF.Threading · 9 unmodified lines
235 }223 }
236 }224 }
237 225
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
238 #endregion269 #endregion
239 270
240 #region [ Methods ]271 #region [ Methods ]
@@ -260,7 +291,7 @@ namespace GSF.Threading · 19 unmodified lines
260 throw new ArgumentException($"Priority {priority} is outside the range between 1 and {PriorityLevels}.", nameof(priority));291 throw new ArgumentException($"Priority {priority} is outside the range between 1 and {PriorityLevels}.", nameof(priority));
261 292
262 m_queues[PriorityLevels - priority].Enqueue(action);293 m_queues[PriorityLevels - priority].Enqueue(action);
263 m_scheduler.SignalItemHandler(this);294 m_scheduler.SignalItemHandler(this, priority);
264 }295 }
265 296
266 /// <summary>297 /// <summary>
@@ -305,20 +336,28 @@ namespace GSF.Threading · 38 unmodified lines
305 }336 }
306 337
307 /// <summary>338 /// <summary>
308 /// Activates the thread if it is not already active.339 /// Attempts to activate the thread at the given priority.
309 /// </summary>340 /// </summary>
310 /// <returns>True if this call to TryActivate caused the thread to be active.</returns>341 /// <param name="priority">The priority at which to activate the thread.</param>
311 internal bool TryActivate()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)
312 {344 {
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();
314 }350 }
315 351
316 /// <summary>352 /// <summary>
317 /// Deactivates the thread.353 /// Completely deactivates the thread, making it available for reactivation at any priority.
318 /// </summary>354 /// </summary>
319 internal void Deactivate()355 internal void Deactivate()
320 {356 {
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();
322 }361 }
323 362
324 /// <summary>363 /// <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