Пример #1
0
        /// <summary>Initializes a new instance of the ThreadAffinityTaskScheduler class with the specified concurrency level.</summary>
        /// <param name="numberOfThreads">The number of threads that should be created and used by this scheduler.</param>
        public ThreadAffinityTaskScheduler(int numberOfThreads, bool staThreads = false, WaitHelperFunc waitHelper = null)
        {
            // Validate arguments
            if (numberOfThreads < 1)
            {
                throw new ArgumentOutOfRangeException("numberOfThreads");
            }

            // Initialize the tasks collection
            _items = new BlockingCollection <IExecuteItem>();

            // CTS to cancel task dispatching
            _terminationCts = new CancellationTokenSource();

            // Create the contexts (threads) to be used by this scheduler
            _threads = Enumerable.Range(0, numberOfThreads).Select(i =>
                                                                   new ThreadWithAffinityContext(_terminationCts.Token, staThreads, waitHelper, Take)).ToList();
        }
Пример #2
0
        /// <summary>
        /// Construct an instance of ThreadWithAffinityContext to used by ThreadAffinityTaskScheduler
        /// </summary>
        internal ThreadWithAffinityContext(CancellationToken token, bool staThread, WaitHelperFunc waitHelper, TakeFunc takeFunc)
        {
            _waitHelper = waitHelper;
            _items      = new BlockingCollection <IExecuteItem>();
            _takeFunc   = takeFunc;
            _cts        = CancellationTokenSource.CreateLinkedTokenSource(token);

            if (_takeFunc == null)
            {
                _takeFunc = Take;
            }

            // this makes our override of SynchronizationContext.Wait get called
            if (_waitHelper == null)
            {
                _waitHelper = WaitHelper;
            }
            else
            {
                base.SetWaitNotificationRequired();
            }

            // use TCS to return SingleThreadSynchronizationContext to the task scheduler
            var tcs = new TaskCompletionSource <TaskScheduler>();

            _thread = new Thread(() =>
            {
                // install on the current thread
                SynchronizationContext.SetSynchronizationContext(this);
                try
                {
                    tcs.SetResult(TaskScheduler.FromCurrentSynchronizationContext()); // the sync. context is ready, return it to the task scheduler

                    // the thread's core task dispatching loop, terminate-able with token
                    while (true)
                    {
                        var executeItem = _takeFunc(_items, _cts.Token);
                        // execute a Task queued by ThreadAffinityTaskScheduler.QueueTask
                        // or a callback queued by SingleThreadSynchronizationContext.Post
                        executeItem.Execute();
                    }
                    ;
                }
                catch (OperationCanceledException)
                {
                    // ignore OperationCanceledException exceptions when terminating
                    if (!_cts.Token.IsCancellationRequested)
                    {
                        throw;
                    }
                }
                finally
                {
                    SynchronizationContext.SetSynchronizationContext(null);
                }
            });

            // make it an STA thread if message pumping is requested
            if (staThread)
            {
                _thread.SetApartmentState(ApartmentState.STA);
            }

            _thread.IsBackground = true;
            _thread.Start();
            this.Scheduler = tcs.Task.Result;
        }