Exemplo n.º 1
0
        /// <summary>Adds a work-stealing queue to the set of queues.</summary>
        /// <param name="wsq">The queue to be added.</param>
        private void AddWsq(WorkStealingQueue <Task> wsq)
        {
            lock (m_wsQueues)
            {
                // Find the next open slot in the array. If we find one,
                // store the queue and we're done.
                int i;
                for (i = 0; i < m_wsQueues.Length; i++)
                {
                    if (m_wsQueues[i] == null)
                    {
                        m_wsQueues[i] = wsq;
                        return;
                    }
                }

                // We couldn't find an open slot, so double the length
                // of the array by creating a new one, copying over,
                // and storing the new one. Here, i == m_wsQueues.Length.
                WorkStealingQueue <Task>[] queues = new WorkStealingQueue <Task> [i * 2];
                Array.Copy(m_wsQueues, queues, i);
                queues[i]  = wsq;
                m_wsQueues = queues;
            }
        }
Exemplo n.º 2
0
 /// <summary>Remove a work-stealing queue from the set of queues.</summary>
 /// <param name="wsq">The work-stealing queue to remove.</param>
 private void RemoveWsq(WorkStealingQueue <Task> wsq)
 {
     lock (m_wsQueues)
     {
         // Find the queue, and if/when we find it, null out its array slot
         for (int i = 0; i < m_wsQueues.Length; i++)
         {
             if (m_wsQueues[i] == wsq)
             {
                 m_wsQueues[i] = null;
             }
         }
     }
 }
Exemplo n.º 3
0
        /// <summary>Queues a task to the scheduler.</summary>
        /// <param name="task">The task to be scheduled.</param>
        protected override void QueueTask(Task task)
        {
            // Make sure the pool is started, e.g. that all threads have been created.
            m_threads.Force();

            // If the task is marked as long-running, give it its own dedicated thread
            // rather than queueing it.
            if ((task.CreationOptions & TaskCreationOptions.LongRunning) != 0)
            {
                new Thread(state => base.TryExecuteTask((Task)state))
                {
                    IsBackground = true
                }.Start(task);
            }
            else
            {
                // Otherwise, insert the work item into a queue, possibly waking a thread.
                // If there's a local queue and the task does not prefer to be in the global queue,
                // add it to the local queue.
                WorkStealingQueue <Task> wsq = m_wsq;
                if (wsq != null && ((task.CreationOptions & TaskCreationOptions.PreferFairness) == 0))
                {
                    // Add to the local queue and notify any waiting threads that work is available.
                    // Races may occur which result in missed event notifications, but they're benign in that
                    // this thread will eventually pick up the work item anyway, as will other threads when another
                    // work item notification is received.
                    wsq.LocalPush(task);
                    if (m_threadsWaiting > 0) // OK to read lock-free.
                    {
                        lock (m_queue) { Monitor.Pulse(m_queue); }
                    }
                }
                // Otherwise, add the work item to the global queue
                else
                {
                    lock (m_queue)
                    {
                        m_queue.Enqueue(task);
                        if (m_threadsWaiting > 0)
                        {
                            Monitor.Pulse(m_queue);
                        }
                    }
                }
            }
        }
Exemplo n.º 4
0
        /// <summary>Gets all of the tasks currently scheduled to this scheduler.</summary>
        /// <returns>An enumerable containing all of the scheduled tasks.</returns>
        protected override IEnumerable <Task> GetScheduledTasks()
        {
            // Keep track of all of the tasks we find
            List <Task> tasks = new List <Task>();

            // Get all of the global tasks.  We use TryEnter so as not to hang
            // a debugger if the lock is held by a frozen thread.
            bool lockTaken = false;

            try
            {
                Monitor.TryEnter(m_queue, ref lockTaken);
                if (lockTaken)
                {
                    tasks.AddRange(m_queue.ToArray());
                }
                else
                {
                    throw new NotSupportedException();
                }
            }
            finally
            {
                if (lockTaken)
                {
                    Monitor.Exit(m_queue);
                }
            }

            // Now get all of the tasks from the work-stealing queues
            WorkStealingQueue <Task>[] queues = m_wsQueues;
            for (int i = 0; i < queues.Length; i++)
            {
                WorkStealingQueue <Task> wsq = queues[i];
                if (wsq != null)
                {
                    tasks.AddRange(wsq.ToArray());
                }
            }

            // Return to the debugger all of the collected task instances
            return(tasks);
        }
Exemplo n.º 5
0
        /// <summary>
        /// The dispatch loop run by each thread in the scheduler.
        /// </summary>
        private void DispatchLoop()
        {
            // Create a new queue for this thread, store it in TLS for later retrieval,
            // and add it to the set of queues for this scheduler.
            WorkStealingQueue <Task> wsq = new WorkStealingQueue <Task>();

            m_wsq = wsq;
            AddWsq(wsq);

            try
            {
                // Until there's no more work to do...
                while (true)
                {
                    Task wi = null;

                    // Search order: (1) local WSQ, (2) global Q, (3) steals from other queues.
                    if (!wsq.LocalPop(ref wi))
                    {
                        // We weren't able to get a task from the local WSQ
                        bool searchedForSteals = false;
                        while (true)
                        {
                            lock (m_queue)
                            {
                                // If shutdown was requested, exit the thread.
                                if (m_shutdown)
                                {
                                    return;
                                }

                                // (2) try the global queue.
                                if (m_queue.Count != 0)
                                {
                                    // We found a work item! Grab it ...
                                    wi = m_queue.Dequeue();
                                    break;
                                }
                                else if (searchedForSteals)
                                {
                                    // Note that we're not waiting for work, and then wait
                                    m_threadsWaiting++;
                                    try { Monitor.Wait(m_queue); }
                                    finally { m_threadsWaiting--; }

                                    // If we were signaled due to shutdown, exit the thread.
                                    if (m_shutdown)
                                    {
                                        return;
                                    }

                                    searchedForSteals = false;
                                    continue;
                                }
                            }

                            // (3) try to steal.
                            WorkStealingQueue <Task>[] wsQueues = m_wsQueues;
                            int i;
                            for (i = 0; i < wsQueues.Length; i++)
                            {
                                WorkStealingQueue <Task> q = wsQueues[i];
                                if (q != null && q != wsq && q.TrySteal(ref wi))
                                {
                                    break;
                                }
                            }

                            if (i != wsQueues.Length)
                            {
                                break;
                            }

                            searchedForSteals = true;
                        }
                    }

                    // ...and Invoke it.
                    TryExecuteTask(wi);
                }
            }
            finally
            {
                RemoveWsq(wsq);
            }
        }