1 //--------------------------------------------------------------------------
3 // Copyright (c) Microsoft Corporation. All rights reserved.
5 // File: StaTaskScheduler.cs
7 //--------------------------------------------------------------------------
9 using System.Collections.Concurrent;
10 using System.Collections.Generic;
13 namespace System.Threading.Tasks.Schedulers
15 /// <summary>Provides a scheduler that uses STA threads.</summary>
16 public sealed class StaTaskScheduler : TaskScheduler, IDisposable
18 /// <summary>Stores the queued tasks to be executed by our pool of STA threads.</summary>
19 private BlockingCollection<Task> _tasks;
20 /// <summary>The STA threads used by the scheduler.</summary>
21 private readonly List<Thread> _threads;
23 /// <summary>Initializes a new instance of the StaTaskScheduler class with the specified concurrency level.</summary>
24 /// <param name="numberOfThreads">The number of threads that should be created and used by this scheduler.</param>
25 public StaTaskScheduler(int numberOfThreads)
28 if (numberOfThreads < 1) throw new ArgumentOutOfRangeException("concurrencyLevel");
30 // Initialize the tasks collection
31 _tasks = new BlockingCollection<Task>();
33 // Create the threads to be used by this scheduler
34 _threads = Enumerable.Range(0, numberOfThreads).Select(i =>
36 var thread = new Thread(() =>
38 // Continually get the next task and try to execute it.
39 // This will continue until the scheduler is disposed and no more tasks remain.
40 foreach (var t in _tasks.GetConsumingEnumerable())
45 thread.IsBackground = true;
46 thread.SetApartmentState(ApartmentState.STA);
50 // Start all of the threads
51 _threads.ForEach(t => t.Start());
54 /// <summary>Queues a Task to be executed by this scheduler.</summary>
55 /// <param name="task">The task to be executed.</param>
56 protected override void QueueTask(Task task)
58 // Push it into the blocking collection of tasks
62 /// <summary>Provides a list of the scheduled tasks for the debugger to consume.</summary>
63 /// <returns>An enumerable of all tasks currently scheduled.</returns>
64 protected override IEnumerable<Task> GetScheduledTasks()
66 // Serialize the contents of the blocking collection of tasks for the debugger
67 return _tasks.ToArray();
70 /// <summary>Determines whether a Task may be inlined.</summary>
71 /// <param name="task">The task to be executed.</param>
72 /// <param name="taskWasPreviouslyQueued">Whether the task was previously queued.</param>
73 /// <returns>true if the task was successfully inlined; otherwise, false.</returns>
74 protected override bool TryExecuteTaskInline(Task task, bool taskWasPreviouslyQueued)
76 // Try to inline if the current thread is STA
78 Thread.CurrentThread.GetApartmentState() == ApartmentState.STA &&
82 /// <summary>Gets the maximum concurrency level supported by this scheduler.</summary>
83 public override int MaximumConcurrencyLevel
85 get { return _threads.Count; }
89 /// Cleans up the scheduler by indicating that no more tasks will be queued.
90 /// This method blocks until all threads successfully shutdown.
96 // Indicate that no new tasks will be coming in
97 _tasks.CompleteAdding();
99 // Wait for all threads to finish processing tasks
100 foreach (var thread in _threads) thread.Join();