Showing the changes to Source/Libraries/GSF.Core.Shared/Threading/LogicalThread.cs (1 of 4 files). Show all
Unified · Split
| @@ -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 | get | 208 | 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 | #endregion | 269 | #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> |