TaskScheduler Clase

Definición

Representa un objeto que controla el trabajo de bajo nivel de tareas de puesta en cola en subprocesos.

public ref class TaskScheduler abstract
public abstract class TaskScheduler
type TaskScheduler = class
Public MustInherit Class TaskScheduler
Herencia
TaskScheduler

Ejemplos

En el ejemplo siguiente se crea un programador de tareas personalizado que limita el número de subprocesos usados por la aplicación. A continuación, inicia dos conjuntos de tareas y muestra información sobre la tarea y el subproceso en el que se ejecuta la tarea.

using System;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;

class Example
{
   static void Main()
   {
       // Create a scheduler that uses two threads.
       LimitedConcurrencyLevelTaskScheduler lcts = new LimitedConcurrencyLevelTaskScheduler(2);
       List<Task> tasks = new List<Task>();

       // Create a TaskFactory and pass it our custom scheduler.
       TaskFactory factory = new TaskFactory(lcts);
       CancellationTokenSource cts = new CancellationTokenSource();

       // Use our factory to run a set of tasks.
       Object lockObj = new Object();
       int outputItem = 0;

       for (int tCtr = 0; tCtr <= 4; tCtr++) {
          int iteration = tCtr;
          Task t = factory.StartNew(() => {
                                       for (int i = 0; i < 1000; i++) {
                                          lock (lockObj) {
                                             Console.Write("{0} in task t-{1} on thread {2}   ",
                                                           i, iteration, Thread.CurrentThread.ManagedThreadId);
                                             outputItem++;
                                             if (outputItem % 3 == 0)
                                                Console.WriteLine();
                                          }
                                       }
                                    }, cts.Token);
          tasks.Add(t);
      }
      // Use it to run a second set of tasks.
      for (int tCtr = 0; tCtr <= 4; tCtr++) {
         int iteration = tCtr;
         Task t1 = factory.StartNew(() => {
                                       for (int outer = 0; outer <= 10; outer++) {
                                          for (int i = 0x21; i <= 0x7E; i++) {
                                             lock (lockObj) {
                                                Console.Write("'{0}' in task t1-{1} on thread {2}   ",
                                                              Convert.ToChar(i), iteration, Thread.CurrentThread.ManagedThreadId);
                                                outputItem++;
                                                if (outputItem % 3 == 0)
                                                   Console.WriteLine();
                                             }
                                          }
                                       }
                                    }, cts.Token);
         tasks.Add(t1);
      }

      // Wait for the tasks to complete before displaying a completion message.
      Task.WaitAll(tasks.ToArray());
      cts.Dispose();
      Console.WriteLine("\n\nSuccessful completion.");
   }
}

// Provides a task scheduler that ensures a maximum concurrency level while
// running on top of the thread pool.
public class LimitedConcurrencyLevelTaskScheduler : TaskScheduler
{
   // Indicates whether the current thread is processing work items.
   [ThreadStatic]
   private static bool _currentThreadIsProcessingItems;

  // The list of tasks to be executed
   private readonly LinkedList<Task> _tasks = new LinkedList<Task>(); // protected by lock(_tasks)

   // The maximum concurrency level allowed by this scheduler.
   private readonly int _maxDegreeOfParallelism;

   // Indicates whether the scheduler is currently processing work items.
   private int _delegatesQueuedOrRunning = 0;

   // Creates a new instance with the specified degree of parallelism.
   public LimitedConcurrencyLevelTaskScheduler(int maxDegreeOfParallelism)
   {
       if (maxDegreeOfParallelism < 1) throw new ArgumentOutOfRangeException("maxDegreeOfParallelism");
       _maxDegreeOfParallelism = maxDegreeOfParallelism;
   }

   // Queues a task to the scheduler.
   protected sealed override void QueueTask(Task task)
   {
      // Add the task to the list of tasks to be processed.  If there aren't enough
      // delegates currently queued or running to process tasks, schedule another.
       lock (_tasks)
       {
           _tasks.AddLast(task);
           if (_delegatesQueuedOrRunning < _maxDegreeOfParallelism)
           {
               ++_delegatesQueuedOrRunning;
               NotifyThreadPoolOfPendingWork();
           }
       }
   }

   // Inform the ThreadPool that there's work to be executed for this scheduler.
   private void NotifyThreadPoolOfPendingWork()
   {
       ThreadPool.UnsafeQueueUserWorkItem(_ =>
       {
           // Note that the current thread is now processing work items.
           // This is necessary to enable inlining of tasks into this thread.
           _currentThreadIsProcessingItems = true;
           try
           {
               // Process all available items in the queue.
               while (true)
               {
                   Task item;
                   lock (_tasks)
                   {
                       // When there are no more items to be processed,
                       // note that we're done processing, and get out.
                       if (_tasks.Count == 0)
                       {
                           --_delegatesQueuedOrRunning;
                           break;
                       }

                       // Get the next item from the queue
                       item = _tasks.First.Value;
                       _tasks.RemoveFirst();
                   }

                   // Execute the task we pulled out of the queue
                   base.TryExecuteTask(item);
               }
           }
           // We're done processing items on the current thread
           finally { _currentThreadIsProcessingItems = false; }
       }, null);
   }

   // Attempts to execute the specified task on the current thread.
   protected sealed override bool TryExecuteTaskInline(Task task, bool taskWasPreviouslyQueued)
   {
       // If this thread isn't already processing a task, we don't support inlining
       if (!_currentThreadIsProcessingItems) return false;

       // If the task was previously queued, remove it from the queue
       if (taskWasPreviouslyQueued)
          // Try to run the task.
          if (TryDequeue(task))
            return base.TryExecuteTask(task);
          else
             return false;
       else
          return base.TryExecuteTask(task);
   }

   // Attempt to remove a previously scheduled task from the scheduler.
   protected sealed override bool TryDequeue(Task task)
   {
       lock (_tasks) return _tasks.Remove(task);
   }

   // Gets the maximum concurrency level supported by this scheduler.
   public sealed override int MaximumConcurrencyLevel { get { return _maxDegreeOfParallelism; } }

   // Gets an enumerable of the tasks currently scheduled on this scheduler.
   protected sealed override IEnumerable<Task> GetScheduledTasks()
   {
       bool lockTaken = false;
       try
       {
           Monitor.TryEnter(_tasks, ref lockTaken);
           if (lockTaken) return _tasks;
           else throw new NotSupportedException();
       }
       finally
       {
           if (lockTaken) Monitor.Exit(_tasks);
       }
   }
}
// The following is a portion of the output from a single run of the example:
//    'T' in task t1-4 on thread 3   'U' in task t1-4 on thread 3   'V' in task t1-4 on thread 3
//    'W' in task t1-4 on thread 3   'X' in task t1-4 on thread 3   'Y' in task t1-4 on thread 3
//    'Z' in task t1-4 on thread 3   '[' in task t1-4 on thread 3   '\' in task t1-4 on thread 3
//    ']' in task t1-4 on thread 3   '^' in task t1-4 on thread 3   '_' in task t1-4 on thread 3
//    '`' in task t1-4 on thread 3   'a' in task t1-4 on thread 3   'b' in task t1-4 on thread 3
//    'c' in task t1-4 on thread 3   'd' in task t1-4 on thread 3   'e' in task t1-4 on thread 3
//    'f' in task t1-4 on thread 3   'g' in task t1-4 on thread 3   'h' in task t1-4 on thread 3
//    'i' in task t1-4 on thread 3   'j' in task t1-4 on thread 3   'k' in task t1-4 on thread 3
//    'l' in task t1-4 on thread 3   'm' in task t1-4 on thread 3   'n' in task t1-4 on thread 3
//    'o' in task t1-4 on thread 3   'p' in task t1-4 on thread 3   ']' in task t1-2 on thread 4
//    '^' in task t1-2 on thread 4   '_' in task t1-2 on thread 4   '`' in task t1-2 on thread 4
//    'a' in task t1-2 on thread 4   'b' in task t1-2 on thread 4   'c' in task t1-2 on thread 4
//    'd' in task t1-2 on thread 4   'e' in task t1-2 on thread 4   'f' in task t1-2 on thread 4
//    'g' in task t1-2 on thread 4   'h' in task t1-2 on thread 4   'i' in task t1-2 on thread 4
//    'j' in task t1-2 on thread 4   'k' in task t1-2 on thread 4   'l' in task t1-2 on thread 4
//    'm' in task t1-2 on thread 4   'n' in task t1-2 on thread 4   'o' in task t1-2 on thread 4
//    'p' in task t1-2 on thread 4   'q' in task t1-2 on thread 4   'r' in task t1-2 on thread 4
//    's' in task t1-2 on thread 4   't' in task t1-2 on thread 4   'u' in task t1-2 on thread 4
//    'v' in task t1-2 on thread 4   'w' in task t1-2 on thread 4   'x' in task t1-2 on thread 4
//    'y' in task t1-2 on thread 4   'z' in task t1-2 on thread 4   '{' in task t1-2 on thread 4
//    '|' in task t1-2 on thread 4   '}' in task t1-2 on thread 4   '~' in task t1-2 on thread 4
//    'q' in task t1-4 on thread 3   'r' in task t1-4 on thread 3   's' in task t1-4 on thread 3
//    't' in task t1-4 on thread 3   'u' in task t1-4 on thread 3   'v' in task t1-4 on thread 3
//    'w' in task t1-4 on thread 3   'x' in task t1-4 on thread 3   'y' in task t1-4 on thread 3
//    'z' in task t1-4 on thread 3   '{' in task t1-4 on thread 3   '|' in task t1-4 on thread 3

Comentarios

La TaskScheduler clase representa un programador de tareas. Un programador de tareas garantiza que el trabajo de una tarea se ejecute finalmente.

El programador de tareas predeterminado proporciona robos de trabajos para lograr el equilibrado de carga, inyección/retirada de subprocesos para obtener la mayor capacidad de procesamiento posible y un buen rendimiento general. Debe ser suficiente para la mayoría de los escenarios.

La TaskScheduler clase también actúa como punto de extensión para toda la lógica de programación personalizable. Esto incluye mecanismos como cómo programar una tarea para su ejecución y cómo se deben exponer las tareas programadas a los depuradores. Si necesita una funcionalidad especial, puede crear un programador personalizado y habilitarlo para tareas o consultas específicas.

El programador de tareas predeterminado y el grupo de subprocesos

El programador predeterminado para la biblioteca de procesamiento paralelo y PLINQ utiliza el grupo de subprocesos de .NET, que está representado por la clase ThreadPool, para encolar y ejecutar tareas. El grupo de subprocesos utiliza la información proporcionada por el tipo Task para así llevar a cabo de forma eficaz el detallado paralelismo (unidades de trabajo de corta duración) que suelen implicar las tareas y consultas paralelas.

Cola global contra colas locales

El grupo de subprocesos mantiene una cola de trabajo FIFO global (first-in, first-out) para los subprocesos de cada dominio de aplicación. Cada vez que un programa llama al método ThreadPool.QueueUserWorkItem (o ThreadPool.UnsafeQueueUserWorkItem), el trabajo se coloca en esta cola compartida y finalmente se desencola sobre el siguiente subproceso que quede disponible. A partir de .NET Framework 4, esta cola utiliza un algoritmo sin bloqueo similar a una clase ConcurrentQueue<T>. Mediante el uso de esta implementación sin bloqueo, el grupo de subprocesos necesita menos tiempo para encolar y desencolar elementos de trabajo. Esta ventaja de rendimiento está disponible para todos los programas que usan el grupo de subprocesos.

Las tareas de nivel superior, que son tareas que no se crean en el contexto de otra tarea, se colocan en la cola global como cualquier otro elemento de trabajo. Sin embargo, las tareas anidadas o secundarias, que se crean en el contexto de otra tarea, se controlan de forma bastante distinta. Una tarea secundaria o anidada se coloca en una cola local que es específica del subproceso en el que la tarea primaria se está ejecutando. La tarea primaria puede ser una tarea de nivel superior o también puede ser el elemento secundario de otra tarea. Cuando este subproceso está listo para más trabajo, primero busca en la cola local. Si los elementos de trabajo están esperando allí, se puede acceder a ellos rápidamente. Se accede a las colas locales con un enfoque LIFO (último en entrar, primero en salir) para así mantener el carácter local de la caché y reducir la contención. Para más información sobre las tareas secundarias y las tareas anidadas, véase Tareas secundarias adjuntadas y separadas.

El uso de colas locales no solo reduce la presión sobre la cola global, sino que también aprovecha la localidad de datos. Los elementos de tarea presentes en la cola local hacen referencia normalmente a las estructuras de datos que se encuentran en la memoria físicamente cerca unas de otras. En estos casos, los datos ya están en la memoria caché después de que se haya ejecutado la primera tarea y se pueda acceder a ellos rápidamente. Tanto Parallel LINQ (PLINQ) como la clase Parallel hacen un uso significativo de tareas anidadas y tareas secundarias, y logran importantes mejoras de rapidez mediante el uso de colas de trabajo locales.

Robo de trabajo

A partir de .NET Framework 4, el grupo de subprocesos también incluye un algoritmo de robo de tareas para ayudar a asegurarse de que no haya subprocesos inactivos mientras que otros todavía tengan trabajo en sus listas. Cuando un subproceso ThreadPool está listo para más trabajo, examina primero el encabezado de la cola local, a continuación, en la cola global y después en las colas locales de otros subprocesos. Si encuentra un elemento de trabajo en la cola local de otro subproceso, aplica primero heurística para asegurarse de que puede ejecutar el trabajo eficazmente. Si es posible, se saca de la cola el elemento de trabajo situado al final la cola (en orden FIFO). Esto reduce la contención en cada cola local y mantiene la situación de los datos. Esta arquitectura ayuda al equilibrio de carga del grupo de subprocesos a funcionar de forma más eficaz que las versiones anteriores.

Tareas de larga duración

Es posible que desee impedir explícitamente que una tarea se coloque en una cola local. Por ejemplo, puede saber que un elemento de trabajo determinado se ejecutará durante un tiempo relativamente largo y es probable que bloquee el resto de los elementos de trabajo de la cola local. En este caso, puede especificar la opción System.Threading.Tasks.TaskCreationOptions, que proporciona una sugerencia al programador que le indica que tal vez es necesario un subproceso adicional para que la tarea no bloquee el progreso de otros subproceso o elementos de trabajo de la cola local. Con esta opción se evita totalmente el grupo de subprocesos, incluidas las colas globales y locales.

Inserción de tareas

En algunos casos, cuando se espera un Task, este puede ser ejecutado de forma síncrona en el subproceso que está realizando la operación de espera. Esto mejora el rendimiento evitando la necesidad de un subproceso adicional y usando en su lugar el subproceso existente, que de otro modo se habría bloqueado. Para evitar errores debidos a reentradas, la inserción de tareas solo se produce cuando el destino de espera se encuentra en la cola local del subproceso correspondiente.

Especificar un contexto de sincronización

Puede usar el TaskScheduler.FromCurrentSynchronizationContext método para especificar que se debe programar una tarea para ejecutarse en un subproceso determinado. Esto resulta útil en marcos como Windows Forms y Windows Presentation Foundation, donde el acceso a objetos de interfaz de usuario suele estar restringido al código que se ejecuta en el mismo subproceso en el que se creó el objeto de interfaz de usuario.

En el ejemplo siguiente se usa el TaskScheduler.FromCurrentSynchronizationContext método en una aplicación de Windows Presentation Foundation (WPF) para programar una tarea en el mismo subproceso en el que se creó el control de interfaz de usuario (UI). En el ejemplo se crea un mosaico de imágenes seleccionadas aleatoriamente desde un directorio especificado. Los objetos WPF se usan para cargar y cambiar el tamaño de las imágenes. A continuación, los píxeles sin procesar se pasan a una tarea que usa un bucle For para escribir los datos de los píxeles en una gran matriz de bytes individuales. No se requiere sincronización porque no hay dos iconos que ocupen los mismos elementos de matriz. Los iconos también se pueden escribir en cualquier orden porque su posición se calcula independientemente de cualquier otro icono. A continuación, esta matriz grande se le pasa a una tarea que se ejecuta en el subproceso de la interfaz de usuario, donde los datos de los píxeles se cargan en un control de imagen.

En el ejemplo, los datos se mueven fuera del subproceso de la interfaz de usuario, se modifican utilizando bucles paralelos y objetos Task, y luego se pasan a una tarea que se ejecuta en el subproceso de la interfaz de usuario. Este enfoque es útil cuando tiene que usar la biblioteca paralela de tareas para realizar operaciones que no son compatibles con la API de WPF o que no son lo suficientemente rápidas. Otra manera de crear un mosaico de imágenes en WPF es usar un System.Windows.Controls.WrapPanel control y agregarle imágenes. El WrapPanel lleva a cabo el trabajo de posicionar los mosaicos. Sin embargo, este trabajo solo se puede realizar en el subproceso de la interfaz de usuario.

using System;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Media;
using System.Windows.Media.Imaging;

namespace WPF_CS1
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        private int fileCount;
        int colCount;
        int rowCount;
        private int tilePixelHeight;
        private int tilePixelWidth;
        private int largeImagePixelHeight;
        private int largeImagePixelWidth;
        private int largeImageStride;
        PixelFormat format;
        BitmapPalette palette = null;

        public MainWindow()
        {
            InitializeComponent();

            // For this example, values are hard-coded to a mosaic of 8x8 tiles.
            // Each tile is 50 pixels high and 66 pixels wide and 32 bits per pixel.
            colCount = 12;
            rowCount = 8;
            tilePixelHeight = 50;
            tilePixelWidth = 66;
            largeImagePixelHeight = tilePixelHeight * rowCount;
            largeImagePixelWidth = tilePixelWidth * colCount;
            largeImageStride = largeImagePixelWidth * (32 / 8);
            this.Width = largeImagePixelWidth + 40;
            image.Width = largeImagePixelWidth;
            image.Height = largeImagePixelHeight;
        }

        private void button_Click(object sender, RoutedEventArgs e)
        {

            // For best results use 1024 x 768 jpg files at 32bpp.
            string[] files = System.IO.Directory.GetFiles(@"C:\Users\Public\Pictures\Sample Pictures\", "*.jpg");

            fileCount = files.Length;
            Task<byte[]>[] images = new Task<byte[]>[fileCount];
            for (int i = 0; i < fileCount; i++)
            {
                int x = i;
                images[x] = Task.Factory.StartNew(() => LoadImage(files[x]));
            }

            // When they've all been loaded, tile them into a single byte array.
            var tiledImage = Task.Factory.ContinueWhenAll(
                images, (i) => TileImages(i));

            // We are currently on the UI thread. Save the sync context and pass it to
            // the next task so that it can access the UI control "image".
            var UISyncContext = TaskScheduler.FromCurrentSynchronizationContext();

            // On the UI thread, put the bytes into a bitmap and
            // display it in the Image control.
            var t3 = tiledImage.ContinueWith((antecedent) =>
            {
                // Get System DPI.
                Matrix m = PresentationSource.FromVisual(Application.Current.MainWindow)
                                            .CompositionTarget.TransformToDevice;
                double dpiX = m.M11;
                double dpiY = m.M22;

                BitmapSource bms = BitmapSource.Create(largeImagePixelWidth,
                    largeImagePixelHeight,
                    dpiX,
                    dpiY,
                    format,
                    palette, //use default palette
                    antecedent.Result,
                    largeImageStride);
                image.Source = bms;
            }, UISyncContext);
        }

        byte[] LoadImage(string filename)
        {
            // Use the WPF BitmapImage class to load and
            // resize the bitmap. NOTE: Only 32bpp formats are supported correctly.
            // Support for additional color formats is left as an exercise
            // for the reader. For more information, see documentation for ColorConvertedBitmap.

            BitmapImage bitmapImage = new BitmapImage();
            bitmapImage.BeginInit();
            bitmapImage.UriSource = new Uri(filename);
            bitmapImage.DecodePixelHeight = tilePixelHeight;
            bitmapImage.DecodePixelWidth = tilePixelWidth;
            bitmapImage.EndInit();

            format = bitmapImage.Format;
            int size = (int)(bitmapImage.Height * bitmapImage.Width);
            int stride = (int)bitmapImage.Width * 4;
            byte[] dest = new byte[stride * tilePixelHeight];

            bitmapImage.CopyPixels(dest, stride, 0);

            return dest;
        }

        int Stride(int pixelWidth, int bitsPerPixel)
        {
            return (((pixelWidth * bitsPerPixel + 31) / 32) * 4);
        }

        // Map the individual image tiles to the large image
        // in parallel. Any kind of raw image manipulation can be
        // done here because we are not attempting to access any
        // WPF controls from multiple threads.
        byte[] TileImages(Task<byte[]>[] sourceImages)
        {
            byte[] largeImage = new byte[largeImagePixelHeight * largeImageStride];
            int tileImageStride = tilePixelWidth * 4; // hard coded to 32bpp

            Random rand = new Random();
            Parallel.For(0, rowCount * colCount, (i) =>
            {
                // Pick one of the images at random for this tile.
                int cur = rand.Next(0, sourceImages.Length);
                byte[] pixels = sourceImages[cur].Result;

                // Get the starting index for this tile.
                int row = i / colCount;
                int col = (int)(i % colCount);
                int idx = ((row * (largeImageStride * tilePixelHeight)) + (col * tileImageStride));

                // Write the pixels for the current tile. The pixels are not contiguous
                // in the array, therefore we have to advance the index by the image stride
                // (minus the stride of the tile) for each scanline of the tile.
                int tileImageIndex = 0;
                for (int j = 0; j < tilePixelHeight; j++)
                {
                    // Write the next scanline for this tile.
                    for (int k = 0; k < tileImageStride; k++)
                    {
                        largeImage[idx++] = pixels[tileImageIndex++];
                    }
                    // Advance to the beginning of the next scanline.
                    idx += largeImageStride - tileImageStride;
                }
            });
            return largeImage;
        }
    }
}

Para crear el ejemplo, cree un proyecto de aplicación WPF en Visual Studio y asígnelo el nombre WPF_CS1 (para un proyecto WPF de C#) o WPF_VB1 (para un proyecto de WPF de Visual Basic). A continuación, haga lo siguiente:

  1. En la vista de diseño, arrastre un Image control desde el Cuadro de herramientas a la esquina superior izquierda de la superficie de diseño. En el cuadro de texto Nombre de la ventana Propiedades , asigne al control el nombre "image".

  2. Arrastre un Button control desde el Cuadro de herramientas hasta la parte inferior izquierda de la ventana de la aplicación. En la vista XAML, especifique la Content propiedad del botón como "Crear un mosaico" y especifique su Width propiedad como "100". Conecte el Click evento con el button_Click controlador de eventos definido en el código del ejemplo agregando Click="button_Click" al <Button> elemento . En el cuadro de texto Nombre de la ventana Propiedades , asigne al control el nombre "button".

  3. Reemplace todo el contenido del archivo MainWindow.xaml.cs o MainWindow.xaml.vb por el código de este ejemplo. Para un proyecto de WPF de C#, asegúrese de que el nombre del área de trabajo coincide con el nombre del proyecto.

  4. En el ejemplo se leen imágenes JPEG de un directorio denominado C:\Users\Public\Pictures\Sample Pictures. Cree el directorio y coloque algunas imágenes en él o cambie la ruta de acceso para hacer referencia a otro directorio que contiene imágenes.

Este ejemplo tiene algunas limitaciones. Por ejemplo, solo se admiten imágenes de 32 bits por píxel; Las imágenes en otros formatos están dañadas por el BitmapImage objeto durante la operación de cambio de tamaño. Además, todas las imágenes de origen han de ser más grandes que el tamaño del mosaico. Como ejercicio adicional, puede agregar funcionalidad para controlar varios formatos de píxeles y tamaños de archivo.

Constructores

Nombre Description
TaskScheduler()

Inicializa el TaskScheduler.

Propiedades

Nombre Description
Current

Obtiene el TaskScheduler asociado a la tarea que se está ejecutando actualmente.

Default

Obtiene la instancia predeterminada TaskScheduler proporcionada por .NET.

Id

Obtiene el identificador único de este TaskSchedulerobjeto .

MaximumConcurrencyLevel

Indica el nivel máximo de simultaneidad que TaskScheduler puede admitir.

Métodos

Nombre Description
Equals(Object)

Determina si el objeto especificado es igual al objeto actual.

(Heredado de Object)
Finalize()

Libera todos los recursos asociados a este programador.

FromCurrentSynchronizationContext()

Crea un TaskScheduler asociado al objeto actual SynchronizationContext.

GetHashCode()

Actúa como función hash predeterminada.

(Heredado de Object)
GetScheduledTasks()

Solo para la compatibilidad con el depurador, genera una enumerable de Task instancias actualmente en cola al programador que espera a ejecutarse.

GetType()

Obtiene el Type de la instancia actual.

(Heredado de Object)
MemberwiseClone()

Crea una copia superficial del Objectactual.

(Heredado de Object)
QueueTask(Task)

Pone en cola un Task objeto al programador.

ToString()

Devuelve una cadena que representa el objeto actual.

(Heredado de Object)
TryDequeue(Task)

Intenta anular la cola de un Task objeto que se puso en cola anteriormente en este programador.

TryExecuteTask(Task)

Intenta ejecutar el proporcionado Task en este programador.

TryExecuteTaskInline(Task, Boolean)

Determina si el proporcionado Task se puede ejecutar de forma sincrónica en esta llamada y, si es posible, lo ejecuta.

Eventos

Nombre Description
UnobservedTaskException

Se produce cuando una excepción no atendida de una tarea errónea está a punto de desencadenar la directiva de escalación de excepciones, que, de forma predeterminada, finalizaría el proceso.

Se aplica a

Seguridad para subprocesos

Todos los miembros del tipo abstracto TaskScheduler son seguros para subprocesos y se pueden usar de varios subprocesos simultáneamente.

Consulte también