System.Threading.Tasks.Task osztály

Megjegyzés:

Ez a cikk kiegészítő megjegyzéseket tartalmaz az API referenciadokumentációjához.

Az Task osztály egyetlen olyan műveletet jelöl, amely nem ad vissza értéket, és általában aszinkron módon hajtja végre. Task az objektumok a . NET-keretrendszer 4-ben először bevezetett feladatalapú aszinkron minta egyik központi összetevői. Mivel a Task objektum által végzett munka általában aszinkron módon hajtódik végre egy szálkészlet szálon, nem pedig szinkron módon a fő alkalmazásszálon, a Status tulajdonságot, valamint a IsCanceled, IsCompleted és IsFaulted tulajdonságokat használhatja a tevékenység állapotának meghatározásához. Leggyakrabban lambda kifejezéssel adhatja meg a feladat végrehajtásához szükséges munkát.

Értékek visszaadása esetén az osztályt Task<TResult> kell használnia.

Feladat példányosítása

Az alábbi példa négy feladatot hoz létre és hajt végre. Három feladat hajt végre egy Action<T> nevű action delegáltat, amely elfogad egy Object típusú argumentumot. A negyedik tevékenység végrehajt egy lambda kifejezést (egy meghatalmazottat Action ), amely a feladatlétrehozási metódus hívásában beágyazottan van definiálva. Minden feladat példányosítva van, és más módon fut:

  • A Task t1 példányosítása a Feladat osztály konstruktorának hívásával történik, de a Start() metódus csak akkor indítható, ha a feladat t2 már elindult.

  • A feladat t2 példányosítása és elindítása egyetlen metódushívásban történik a TaskFactory.StartNew(Action<Object>, Object) metódus meghívásával.

  • A feladat t3 példányosítása és elindítása egyetlen metódushívásban történik a Run(Action) metódus meghívásával.

  • A feladat t4 szinkron módon lesz végrehajtva a fő szálon a RunSynchronously() metódus meghívásával.

Mivel a feladat t4 szinkron módon fut, a fő alkalmazásszálon hajtja végre. A fennmaradó feladatok általában egy vagy több szálkészletszálon hajtanak végre aszinkron módon.

using System;
using System.Threading;
using System.Threading.Tasks;

class Example1
{
    static void Main()
    {
        Action<object> action = (object obj) =>
                                {
                                    Console.WriteLine("Task={0}, obj={1}, Thread={2}",
                                    Task.CurrentId, obj,
                                    Thread.CurrentThread.ManagedThreadId);
                                };

        // Create a task but do not start it.
        Task t1 = new Task(action, "alpha");

        // Construct a started task
        Task t2 = Task.Factory.StartNew(action, "beta");
        // Block the main thread to demonstrate that t2 is executing
        t2.Wait();

        // Launch t1 
        t1.Start();
        Console.WriteLine($"t1 has been launched. (Main Thread={Thread.CurrentThread.ManagedThreadId})");
        // Wait for the task to finish.
        t1.Wait();

        // Construct a started task using Task.Run.
        String taskData = "delta";
        Task t3 = Task.Run(() =>
        {
            Console.WriteLine("Task={0}, obj={1}, Thread={2}",
                                                     Task.CurrentId, taskData,
                                                      Thread.CurrentThread.ManagedThreadId);
        });
        // Wait for the task to finish.
        t3.Wait();

        // Construct an unstarted task
        Task t4 = new Task(action, "gamma");
        // Run it synchronously
        t4.RunSynchronously();
        // Although the task was run synchronously, it is a good practice
        // to wait for it in the event exceptions were thrown by the task.
        t4.Wait();
    }
}
// The example displays output like the following:
//       Task=1, obj=beta, Thread=3
//       t1 has been launched. (Main Thread=1)
//       Task=2, obj=alpha, Thread=4
//       Task=3, obj=delta, Thread=3
//       Task=4, obj=gamma, Thread=1
open System.Threading
open System.Threading.Tasks

let action =
    fun (obj: obj) -> printfn $"Task={Task.CurrentId}, obj={obj}, Thread={Thread.CurrentThread.ManagedThreadId}"

// Create a task but do not start it.
let t1 = new Task(action, "alpha")

// Construct a started task
let t2 = Task.Factory.StartNew(action, "beta")
// Block the main thread to demonstrate that t2 is executing
t2.Wait()

// Launch t1
t1.Start()
printfn $"t1 has been launched. (Main Thread={Thread.CurrentThread.ManagedThreadId})"
// Wait for the task to finish.
t1.Wait()

// Construct a started task using Task.Run.
let taskData = "delta"

let t3 =
    Task.Run(fun () -> printfn $"Task={Task.CurrentId}, obj={taskData}, Thread={Thread.CurrentThread.ManagedThreadId}")
// Wait for the task to finish.
t3.Wait()

// Construct an unstarted task
let t4 = new Task(action, "gamma")
// Run it synchronously
t4.RunSynchronously()
// Although the task was run synchronously, it is a good practice
// to wait for it in the event exceptions were thrown by the task.
t4.Wait()


// The example displays output like the following:
//       Task=1, obj=beta, Thread=3
//       t1 has been launched. (Main Thread=1)
//       Task=2, obj=alpha, Thread=4
//       Task=3, obj=delta, Thread=3
//       Task=4, obj=gamma, Thread=1
Imports System.Threading
Imports System.Threading.Tasks

Module Example2
    Public Sub Main()
        Dim action As Action(Of Object) =
              Sub(obj As Object)
                  Console.WriteLine("Task={0}, obj={1}, Thread={2}",
                 Task.CurrentId, obj,
                 Thread.CurrentThread.ManagedThreadId)
              End Sub

        ' Construct an unstarted task
        Dim t1 As New Task(action, "alpha")

        ' Construct a started task
        Dim t2 As Task = Task.Factory.StartNew(action, "beta")
        ' Block the main thread to demonstrate that t2 is executing
        t2.Wait()

        ' Launch t1 
        t1.Start()
        Console.WriteLine("t1 has been launched. (Main Thread={0})",
                          Thread.CurrentThread.ManagedThreadId)
        ' Wait for the task to finish.
        t1.Wait()

        ' Construct a started task using Task.Run.
        Dim taskData As String = "delta"
        Dim t3 As Task = Task.Run(Sub()
                                      Console.WriteLine("Task={0}, obj={1}, Thread={2}",
                                     Task.CurrentId, taskData,
                                     Thread.CurrentThread.ManagedThreadId)
                                  End Sub)
        ' Wait for the task to finish.
        t3.Wait()

        ' Construct an unstarted task
        Dim t4 As New Task(action, "gamma")
        ' Run it synchronously
        t4.RunSynchronously()
        ' Although the task was run synchronously, it is a good practice
        ' to wait for it in the event exceptions were thrown by the task.
        t4.Wait()
    End Sub
End Module
' The example displays output like the following:
'       Task=1, obj=beta, Thread=3
'       t1 has been launched. (Main Thread=1)
'       Task=2, obj=alpha, Thread=3
'       Task=3, obj=delta, Thread=3
'       Task=4, obj=gamma, Thread=1

Feladat létrehozása és végrehajtása

Különböző módokon Task példányokat hozhat létre. A leggyakoribb módszer a statikus Run metódus meghívása. A Run módszer egyszerű módot kínál a tevékenységek alapértelmezett értékek használatával történő elindítására, további paraméterek megkövetelése nélkül. Az alábbi példa a Run(Action) metódust használja egy olyan tevékenység elindításához, amely hurkokat hoz létre, majd megjeleníti a ciklus iterációinak számát:

using System;
using System.Threading.Tasks;

public class Example
{
   public static async Task Main()
   {
      await Task.Run( () => {
                                  // Just loop.
                                  int ctr = 0;
                                  for (ctr = 0; ctr <= 1000000; ctr++)
                                  {}
                                  Console.WriteLine($"Finished {ctr} loop iterations");
                               } );
   }
}
// The example displays the following output:
//        Finished 1000001 loop iterations
open System.Threading.Tasks

let main =
    task {
        do!
            Task.Run(fun () ->
                for i = 0 to 1000000 do
                    printfn $"Finished {i} loop iterations")
    }

main.Wait()

// The example displays the following output:
//        Finished 1000001 loop iterations
Imports System.Threading.Tasks

Module Example1
    Public Sub Main()
        Dim t As Task = Task.Run(Sub()
                                     ' Just loop.
                                     Dim ctr As Integer = 0
                                     For ctr = 0 To 1000000
                                     Next
                                     Console.WriteLine("Finished {0} loop iterations",
                                                    ctr)
                                 End Sub)
        t.Wait()
    End Sub
End Module
' The example displays the following output:
'       Finished 1000001 loop iterations

Alternatív megoldás a statikus TaskFactory.StartNew módszer. A Task.Factory tulajdonság egy objektumot TaskFactory ad vissza. A TaskFactory.StartNew metódus túlterhelései lehetővé teszik, hogy megadja az átadni kívánt paramétereket a feladatlétrehozási beállításoknak és egy feladatütemezőnek. Az alábbi példa a TaskFactory.StartNew metódus használatával indít el egy feladatot. Ez funkcionálisan egyenértékű az előző példában szereplő kóddal.

using System;
using System.Threading.Tasks;

public class Example2
{
    public static void Main()
    {
        Task t = Task.Factory.StartNew(() =>
        {
            // Just loop.
            int ctr = 0;
            for (ctr = 0; ctr <= 1000000; ctr++)
            { }
            Console.WriteLine($"Finished {ctr} loop iterations");
        });
        t.Wait();
    }
}
// The example displays the following output:
//        Finished 1000001 loop iterations
open System.Threading.Tasks

let t =
    Task.Factory.StartNew(fun () ->
        // Just loop.
        for i = 0 to 1000000 do
            printfn $"Finished {i} loop iterations")

t.Wait()


// The example displays the following output:
//        Finished 1000001 loop iterations
Imports System.Threading.Tasks

Module Example3
    Public Sub Main()
        Dim t As Task = Task.Factory.StartNew(Sub()
                                                  ' Just loop.
                                                  Dim ctr As Integer = 0
                                                  For ctr = 0 To 1000000
                                                  Next
                                                  Console.WriteLine("Finished {0} loop iterations",
                                                    ctr)
                                              End Sub)
        t.Wait()
    End Sub
End Module
' The example displays the following output:
'       Finished 1000001 loop iterations

További részletes példákért tekintse meg a feladatalapú aszinkron programozást.

Feladatlétrehozás és -végrehajtás külön

Az Task osztály olyan konstruktorokat is biztosít, amelyek inicializálják a feladatot, de nem ütemezik végrehajtásra. Teljesítménybeli okokból a számítási feladatok létrehozására és ütemezésére előnyben részesített módszer a Task.Run vagy TaskFactory.StartNew metódus, de azokban a forgatókönyvekben, ahol a létrehozást és az ütemezést külön kell választani, használhatja a konstruktorokat, majd meghívhatja a Task.Start metódust a feladat, annak későbbi végrehajtására ütemezésére.

Várjon, amíg egy feladat befejeződik

Mivel a feladatok általában aszinkron módon futnak egy szálpoolszálon, a feladatot létrehozó és elindító szál a feladat példányosítása után is folytatja a végrehajtást. Bizonyos esetekben, amikor a hívó szál a fő alkalmazásszál, az alkalmazás leállhat, mielőtt a feladat ténylegesen megkezdené a végrehajtást. Más esetekben előfordulhat, hogy az alkalmazás logikája megköveteli, hogy a hívó szál csak akkor folytassa a végrehajtást, ha egy vagy több tevékenység végrehajtása befejeződött. A hívószál és az általa indított aszinkron feladatok végrehajtását szinkronizálhatja úgy, hogy meghív egy metódust Wait , hogy megvárjon egy vagy több feladatot.

Ha meg szeretné várni, hogy egy tevékenység befejeződjön, meghívhatja annak metódusát Task.Wait . A metódus hívása blokkolja a Wait hívó szálat, amíg az egyetlen osztálypéldány végrehajtása befejeződik.

Az alábbi példa meghívja a paraméter nélküli Wait() metódust, hogy feltétel nélkül várjon, amíg egy tevékenység befejeződik. A feladat úgy szimulálja a munkát, hogy a Thread.Sleep metódust két másodpercre alvó állapotba hívja.

using System;   
using System.Threading;
using System.Threading.Tasks;

class Program
{
    static Random rand = new Random();

    static void Main()
    {
        // Wait on a single task with no timeout specified.
        Task taskA = Task.Run( () => Thread.Sleep(2000));
        Console.WriteLine($"taskA Status: {taskA.Status}");
        try {
          taskA.Wait();
          Console.WriteLine($"taskA Status: {taskA.Status}");
       } 
       catch (AggregateException) {
          Console.WriteLine("Exception in taskA.");
       }   
    }    
}
// The example displays output like the following:
//     taskA Status: WaitingToRun
//     taskA Status: RanToCompletion
open System
open System.Threading
open System.Threading.Tasks

let rand = Random()

// Wait on a single task with no timeout specified.
let taskA = Task.Run(fun () -> Thread.Sleep 2000)
printfn $"taskA Status: {taskA.Status}"
try 
    taskA.Wait()
    printfn $"taskA Status: {taskA.Status}"

with :? AggregateException ->
    printfn "Exception in taskA."

// The example displays output like the following:
//     taskA Status: WaitingToRun
//     taskA Status: RanToCompletion
Imports System.Threading
Imports System.Threading.Tasks

Module Example4
    Public Sub Main()
        ' Wait on a single task with no timeout specified.
        Dim taskA = Task.Run(Sub() Thread.Sleep(2000))
        Console.WriteLine("taskA Status: {0}", taskA.Status)
        Try
            taskA.Wait()
            Console.WriteLine("taskA Status: {0}", taskA.Status)
        Catch e As AggregateException
            Console.WriteLine("Exception in taskA.")
        End Try
    End Sub
End Module
' The example displays output like the following:
'     taskA Status: WaitingToRun
'     taskA Status: RanToCompletion

Feltételesen megvárhatja a feladat befejezését is. A Wait(Int32) és Wait(TimeSpan) metódusok blokkolják a hívó szálat, amíg a tevékenység befejeződik, vagy eltelik egy időtúllépés, attól függően, hogy melyik történik előbb. Mivel az alábbi példa egy két másodpercig alvó, de egy másodperces időtúllépési értéket definiáló tevékenységet indít el, a hívószál az időtúllépés lejáratáig és a feladat végrehajtása előtt blokkol.

using System;
using System.Threading;
using System.Threading.Tasks;

public class Example5
{
    public static void Main()
    {
        // Wait on a single task with a timeout specified.
        Task taskA = Task.Run(() => Thread.Sleep(2000));
        try
        {
            taskA.Wait(1000);       // Wait for 1 second.
            bool completed = taskA.IsCompleted;
            Console.WriteLine("Task A completed: {0}, Status: {1}",
                             completed, taskA.Status);
            if (!completed)
                Console.WriteLine("Timed out before task A completed.");
        }
        catch (AggregateException)
        {
            Console.WriteLine("Exception in taskA.");
        }
    }
}
// The example displays output like the following:
//     Task A completed: False, Status: Running
//     Timed out before task A completed.
open System
open System.Threading
open System.Threading.Tasks

// Wait on a single task with a timeout specified.
let taskA = Task.Run(fun () -> Thread.Sleep 2000)

try
    taskA.Wait 1000 |> ignore // Wait for 1 second.
    let completed = taskA.IsCompleted
    printfn $"Task A completed: {completed}, Status: {taskA.Status}"

    if not completed then
        printfn "Timed out before task A completed."

with :? AggregateException ->
    printfn "Exception in taskA."


// The example displays output like the following:
//     Task A completed: False, Status: Running
//     Timed out before task A completed.
Imports System.Threading
Imports System.Threading.Tasks

Module Example5
    Public Sub Main()
        ' Wait on a single task with a timeout specified.
        Dim taskA As Task = Task.Run(Sub() Thread.Sleep(2000))
        Try
            taskA.Wait(1000)        ' Wait for 1 second.
            Dim completed As Boolean = taskA.IsCompleted
            Console.WriteLine("Task.Completed: {0}, Status: {1}",
                           completed, taskA.Status)
            If Not completed Then
                Console.WriteLine("Timed out before task A completed.")
            End If
        Catch e As AggregateException
            Console.WriteLine("Exception in taskA.")
        End Try
    End Sub
End Module
' The example displays the following output:
'     Task A completed: False, Status: Running
'     Timed out before task A completed.

A lemondási tokent is megadhatja a Wait(CancellationToken) és a Wait(Int32, CancellationToken) metódusok hívásával. Ha a token tulajdonsága IsCancellationRequested, vagy true válik, miközben a true metódus végrehajtása zajlik, akkor a metódus egy Wait kivételt dob.

Bizonyos esetekben érdemes megvárni a feladatok végrehajtásának első lépését, de nem érdekli, hogy melyik feladatról van szó. Ennek érdekében meghívhatja a(z) Task.WaitAny függvény egyik túlterhelését. Az alábbi példa három feladatot hoz létre, amelyek mindegyike egy véletlenszerű számgenerátor által meghatározott időközönként alvó állapotban van. A WaitAny(Task[]) metódus megvárja az első feladat befejezését. A példa ezután mindhárom tevékenység állapotával kapcsolatos információkat jeleníti meg.

using System;
using System.Threading;
using System.Threading.Tasks;

public class Example4
{
    public static void Main()
    {
        var tasks = new Task[3];
        var rnd = new Random();
        for (int ctr = 0; ctr <= 2; ctr++)
            tasks[ctr] = Task.Run(() => Thread.Sleep(rnd.Next(500, 3000)));

        try
        {
            int index = Task.WaitAny(tasks);
            Console.WriteLine($"Task #{tasks[index].Id} completed first.\n");
            Console.WriteLine("Status of all tasks:");
            foreach (var t in tasks)
                Console.WriteLine($"   Task #{t.Id}: {t.Status}");
        }
        catch (AggregateException)
        {
            Console.WriteLine("An exception occurred.");
        }
    }
}
// The example displays output like the following:
//     Task #1 completed first.
//     
//     Status of all tasks:
//        Task #3: Running
//        Task #1: RanToCompletion
//        Task #4: Running
open System
open System.Threading
open System.Threading.Tasks

let rnd = new Random()

let tasks =
    [| for _ = 0 to 2 do
           Task.Run(fun () -> rnd.Next(500, 3000) |> Thread.Sleep) |]

try
    let index = Task.WaitAny tasks
    printfn $"Task #{tasks[index].Id} completed first.\n"
    printfn "Status of all tasks:"

    for t in tasks do
        printfn $"   Task #{t.Id}: {t.Status}"

with :? AggregateException ->
    printfn "An exception occurred."

// The example displays output like the following:
//     Task #1 completed first.
//
//     Status of all tasks:
//        Task #3: Running
//        Task #1: RanToCompletion
//        Task #4: Running
Imports System.Threading

Module Example8
    Public Sub Main()
        Dim tasks(2) As Task
        Dim rnd As New Random()
        For ctr As Integer = 0 To 2
            tasks(ctr) = Task.Run(Sub() Thread.Sleep(rnd.Next(500, 3000)))
        Next

        Try
            Dim index As Integer = Task.WaitAny(tasks)
            Console.WriteLine("Task #{0} completed first.", tasks(index).Id)
            Console.WriteLine()
            Console.WriteLine("Status of all tasks:")
            For Each t In tasks
                Console.WriteLine("   Task #{0}: {1}", t.Id, t.Status)
            Next
        Catch e As AggregateException
            Console.WriteLine("An exception occurred.")
        End Try
    End Sub
End Module
' The example displays output like the following:
'     Task #1 completed first.
'     
'     Status of all tasks:
'        Task #3: Running
'        Task #1: RanToCompletion
'        Task #4: Running

A metódus meghívásával WaitAll meg is várhatja, hogy az összes feladat befejeződjön. Az alábbi példa tíz feladatot hoz létre, mind a tízet megvárja, majd megjeleníti az állapotukat.

using System;
using System.Threading;
using System.Threading.Tasks;

public class Example3
{
    public static void Main()
    {
        // Wait for all tasks to complete.
        Task[] tasks = new Task[10];
        for (int i = 0; i < 10; i++)
        {
            tasks[i] = Task.Run(() => Thread.Sleep(2000));
        }
        try
        {
            Task.WaitAll(tasks);
        }
        catch (AggregateException ae)
        {
            Console.WriteLine("One or more exceptions occurred: ");
            foreach (var ex in ae.Flatten().InnerExceptions)
                Console.WriteLine($"   {ex.Message}");
        }

        Console.WriteLine("Status of completed tasks:");
        foreach (var t in tasks)
            Console.WriteLine($"   Task #{t.Id}: {t.Status}");
    }
}
// The example displays the following output:
//     Status of completed tasks:
//        Task #2: RanToCompletion
//        Task #1: RanToCompletion
//        Task #3: RanToCompletion
//        Task #4: RanToCompletion
//        Task #6: RanToCompletion
//        Task #5: RanToCompletion
//        Task #7: RanToCompletion
//        Task #8: RanToCompletion
//        Task #9: RanToCompletion
//        Task #10: RanToCompletion
open System
open System.Threading
open System.Threading.Tasks

// Wait for all tasks to complete.
let tasks =
    [| for _ = 0 to 9 do
           Task.Run(fun () -> Thread.Sleep 2000) |]

try
    Task.WaitAll tasks

with :? AggregateException as ae ->
    printfn "One or more exceptions occurred: "

    for ex in ae.Flatten().InnerExceptions do
        printfn $"   {ex.Message}"

printfn "Status of completed tasks:"

for t in tasks do
    printfn $"   Task #{t.Id}: {t.Status}"

// The example displays the following output:
//     Status of completed tasks:
//        Task #2: RanToCompletion
//        Task #1: RanToCompletion
//        Task #3: RanToCompletion
//        Task #4: RanToCompletion
//        Task #6: RanToCompletion
//        Task #5: RanToCompletion
//        Task #7: RanToCompletion
//        Task #8: RanToCompletion
//        Task #9: RanToCompletion
//        Task #10: RanToCompletion
Imports System.Threading
Imports System.Threading.Tasks

Module Example6
    Public Sub Main()
        ' Wait for all tasks to complete.
        Dim tasks(9) As Task
        For i As Integer = 0 To 9
            tasks(i) = Task.Run(Sub() Thread.Sleep(2000))
        Next
        Try
            Task.WaitAll(tasks)
        Catch ae As AggregateException
            Console.WriteLine("One or more exceptions occurred: ")
            For Each ex In ae.Flatten().InnerExceptions
                Console.WriteLine("   {0}", ex.Message)
            Next
        End Try

        Console.WriteLine("Status of completed tasks:")
        For Each t In tasks
            Console.WriteLine("   Task #{0}: {1}", t.Id, t.Status)
        Next
    End Sub
End Module
' The example displays the following output:
'     Status of completed tasks:
'        Task #2: RanToCompletion
'        Task #1: RanToCompletion
'        Task #3: RanToCompletion
'        Task #4: RanToCompletion
'        Task #6: RanToCompletion
'        Task #5: RanToCompletion
'        Task #7: RanToCompletion
'        Task #8: RanToCompletion
'        Task #9: RanToCompletion
'        Task #10: RanToCompletion

Vegye figyelembe, hogy amikor egy vagy több tevékenység befejezésére vár, a futó tevékenységekben szereplő kivételek propagálása a metódust meghívó Wait szálon történik, ahogyan az az alábbi példában is látható. 12 feladatot indít el, amelyek közül három normál módon fejeződik be, és három kivételt eredményez. A fennmaradó hat tevékenység közül három a kezdés előtt megszakad, három pedig a végrehajtás során. A kivételeket dobó metódushívást a WaitAlltry/ blokk kezeli.

using System;
using System.Threading;
using System.Threading.Tasks;

public class Example6
{
    public static void Main()
    {
        // Create a cancellation token and cancel it.
        var source1 = new CancellationTokenSource();
        var token1 = source1.Token;
        source1.Cancel();
        // Create a cancellation token for later cancellation.
        var source2 = new CancellationTokenSource();
        var token2 = source2.Token;

        // Create a series of tasks that will complete, be cancelled, 
        // timeout, or throw an exception.
        Task[] tasks = new Task[12];
        for (int i = 0; i < 12; i++)
        {
            switch (i % 4)
            {
                // Task should run to completion.
                case 0:
                    tasks[i] = Task.Run(() => Thread.Sleep(2000));
                    break;
                // Task should be set to canceled state.
                case 1:
                    tasks[i] = Task.Run(() => Thread.Sleep(2000),
                             token1);
                    break;
                case 2:
                    // Task should throw an exception.
                    tasks[i] = Task.Run(() => { throw new NotSupportedException(); });
                    break;
                case 3:
                    // Task should examine cancellation token.
                    tasks[i] = Task.Run(() =>
                    {
                        Thread.Sleep(2000);
                        if (token2.IsCancellationRequested)
                            token2.ThrowIfCancellationRequested();
                        Thread.Sleep(500);
                    }, token2);
                    break;
            }
        }
        Thread.Sleep(250);
        source2.Cancel();

        try
        {
            Task.WaitAll(tasks);
        }
        catch (AggregateException ae)
        {
            Console.WriteLine("One or more exceptions occurred:");
            foreach (var ex in ae.InnerExceptions)
                Console.WriteLine($"   {ex.GetType().Name}: {ex.Message}");
        }

        Console.WriteLine("\nStatus of tasks:");
        foreach (var t in tasks)
        {
            Console.WriteLine($"   Task #{t.Id}: {t.Status}");
            if (t.Exception != null)
            {
                foreach (var ex in t.Exception.InnerExceptions)
                    Console.WriteLine($"      {ex.GetType().Name}: {ex.Message}");
            }
        }
    }
}
// The example displays output like the following:
//   One or more exceptions occurred:
//      TaskCanceledException: A task was canceled.
//      NotSupportedException: Specified method is not supported.
//      TaskCanceledException: A task was canceled.
//      TaskCanceledException: A task was canceled.
//      NotSupportedException: Specified method is not supported.
//      TaskCanceledException: A task was canceled.
//      TaskCanceledException: A task was canceled.
//      NotSupportedException: Specified method is not supported.
//      TaskCanceledException: A task was canceled.
//   
//   Status of tasks:
//      Task #13: RanToCompletion
//      Task #1: Canceled
//      Task #3: Faulted
//         NotSupportedException: Specified method is not supported.
//      Task #8: Canceled
//      Task #14: RanToCompletion
//      Task #4: Canceled
//      Task #6: Faulted
//         NotSupportedException: Specified method is not supported.
//      Task #7: Canceled
//      Task #15: RanToCompletion
//      Task #9: Canceled
//      Task #11: Faulted
//         NotSupportedException: Specified method is not supported.
//      Task #12: Canceled
open System
open System.Threading
open System.Threading.Tasks

// Create a cancellation token and cancel it.
let source1 = new CancellationTokenSource()
let token1 = source1.Token
source1.Cancel()
// Create a cancellation token for later cancellation.
let source2 = new CancellationTokenSource()
let token2 = source2.Token

// Create a series of tasks that will complete, be cancelled,
// timeout, or throw an exception.
let tasks =
    [| for i in 0..11 do
           match i % 4 with
           // Task should run to completion.
           | 0 -> Task.Run(fun () -> Thread.Sleep 2000)
           // Task should be set to canceled state.
           | 1 -> Task.Run(fun () -> Thread.Sleep 2000, token1)
           // Task should throw an exception.
           | 2 -> Task.Run(fun () -> NotSupportedException())
           // Task should examine cancellation token.
           | _ ->
               Task.Run(fun () ->
                   Thread.Sleep 2000

                   if token2.IsCancellationRequested then
                       token2.ThrowIfCancellationRequested()

                   Thread.Sleep 500, token2) |]


Thread.Sleep 250
source2.Cancel()

try
    Task.WaitAll tasks

with :? AggregateException as ae ->
    printfn "One or more exceptions occurred:"

    for ex in ae.InnerExceptions do
        printfn $"   {ex.GetType().Name}: {ex.Message}"

printfn "\nStatus of tasks:"

for t in tasks do
    printfn $"   Task #{t.Id}: {t.Status}"

    if isNull t.Exception |> not then
        for ex in t.Exception.InnerExceptions do
            printfn $"      {ex.GetType().Name}: {ex.Message}"

// The example displays output like the following:
//   One or more exceptions occurred:
//      TaskCanceledException: A task was canceled.
//      NotSupportedException: Specified method is not supported.
//      TaskCanceledException: A task was canceled.
//      TaskCanceledException: A task was canceled.
//      NotSupportedException: Specified method is not supported.
//      TaskCanceledException: A task was canceled.
//      TaskCanceledException: A task was canceled.
//      NotSupportedException: Specified method is not supported.
//      TaskCanceledException: A task was canceled.
//
//   Status of tasks:
//      Task #13: RanToCompletion
//      Task #1: Canceled
//      Task #3: Faulted
//         NotSupportedException: Specified method is not supported.
//      Task #8: Canceled
//      Task #14: RanToCompletion
//      Task #4: Canceled
//      Task #6: Faulted
//         NotSupportedException: Specified method is not supported.
//      Task #7: Canceled
//      Task #15: RanToCompletion
//      Task #9: Canceled
//      Task #11: Faulted
//         NotSupportedException: Specified method is not supported.
//      Task #12: Canceled
Imports System.Threading
Imports System.Threading.Tasks

Module Example7
    Public Sub Main()
        ' Create a cancellation token and cancel it.
        Dim source1 As New CancellationTokenSource()
        Dim token1 As CancellationToken = source1.Token
        source1.Cancel()
        ' Create a cancellation token for later cancellation.
        Dim source2 As New CancellationTokenSource()
        Dim token2 As CancellationToken = source2.Token

        ' Create a series of tasks that will complete, be cancelled, 
        ' timeout, or throw an exception.
        Dim tasks(11) As Task
        For i As Integer = 0 To 11
            Select Case i Mod 4
             ' Task should run to completion.
                Case 0
                    tasks(i) = Task.Run(Sub() Thread.Sleep(2000))
             ' Task should be set to canceled state.
                Case 1
                    tasks(i) = Task.Run(Sub() Thread.Sleep(2000), token1)
                Case 2
                    ' Task should throw an exception.
                    tasks(i) = Task.Run(Sub()
                                            Throw New NotSupportedException()
                                        End Sub)
                Case 3
                    ' Task should examine cancellation token.
                    tasks(i) = Task.Run(Sub()
                                            Thread.Sleep(2000)
                                            If token2.IsCancellationRequested Then
                                                token2.ThrowIfCancellationRequested()
                                            End If
                                            Thread.Sleep(500)
                                        End Sub, token2)
            End Select
        Next
        Thread.Sleep(250)
        source2.Cancel()

        Try
            Task.WaitAll(tasks)
        Catch ae As AggregateException
            Console.WriteLine("One or more exceptions occurred:")
            For Each ex In ae.InnerExceptions
                Console.WriteLine("   {0}: {1}", ex.GetType().Name, ex.Message)
            Next
        End Try
        Console.WriteLine()

        Console.WriteLine("Status of tasks:")
        For Each t In tasks
            Console.WriteLine("   Task #{0}: {1}", t.Id, t.Status)
            If t.Exception IsNot Nothing Then
                For Each ex In t.Exception.InnerExceptions
                    Console.WriteLine("      {0}: {1}", ex.GetType().Name,
                                 ex.Message)
                Next
            End If
        Next
    End Sub
End Module
' The example displays output like the following:
'   One or more exceptions occurred:
'      TaskCanceledException: A task was canceled.
'      NotSupportedException: Specified method is not supported.
'      TaskCanceledException: A task was canceled.
'      TaskCanceledException: A task was canceled.
'      NotSupportedException: Specified method is not supported.
'      TaskCanceledException: A task was canceled.
'      TaskCanceledException: A task was canceled.
'      NotSupportedException: Specified method is not supported.
'      TaskCanceledException: A task was canceled.
'   
'   Status of tasks:
'      Task #13: RanToCompletion
'      Task #1: Canceled
'      Task #3: Faulted
'         NotSupportedException: Specified method is not supported.
'      Task #8: Canceled
'      Task #14: RanToCompletion
'      Task #4: Canceled
'      Task #6: Faulted
'         NotSupportedException: Specified method is not supported.
'      Task #7: Canceled
'      Task #15: RanToCompletion
'      Task #9: Canceled
'      Task #11: Faulted
'         NotSupportedException: Specified method is not supported.
'      Task #12: Canceled

A feladatalapú aszinkron műveletek kivételkezelésével kapcsolatos további információkért lásd a Kivételkezelés című témakört.

Feladatok és kultúra

A .NET Framework 4.6-ot célzó asztali alkalmazásokkal kezdve a feladatokat létrehozó és meghívó szál kultúrája a szál környezetének részévé válik. Vagyis a tevékenység végrehajtásához használt szál jelenlegi kultúrájától függetlenül a tevékenység jelenlegi kultúrája a hívószál kultúrája. Azon alkalmazások esetében, amelyek a .NET-keretrendszer 4.6 előtti verzióit célozzák meg, a feladat kultúrája annak a szálnak a kultúrája, amelyen a feladat végrehajtja. További információt a témakör "Kultúra és feladatalapú aszinkron műveletek" című szakaszában CultureInfo talál.

Megjegyzés:

Az áruházbeli alkalmazások a Windows futtatókörnyezetet követik az alapértelmezett kultúra beállításában és lekérésében.

Hibakereső fejlesztőknek

Az egyéni hibakeresőket implementáló fejlesztők számára a feladat több belső és privát tagja hasznos lehet (ezek kiadásról kiadásra változhatnak). A m_taskId mező a tulajdonság háttértárolójaként Id szolgál, azonban a mező közvetlen elérése hibakeresőből hatékonyabb lehet, mint ugyanazt az értéket elérni a tulajdonság getter metódusával (a s_taskIdCounter számlálóval lekérhető a tevékenység következő elérhető azonosítója). Hasonlóképpen, a m_stateFlags mező a tevékenység aktuális életciklus-szakaszára vonatkozó információkat tárolja, és ezek az információk a Status tulajdonságon keresztül is elérhetők. A m_action mező a tevékenység delegáltjára mutató hivatkozást tárolja, a m_stateObject mező pedig a fejlesztő által a tevékenységnek átadott aszinkron állapotot tárolja. Végül a veremkereteket elemző hibakeresők számára a InternalWait metódus egy lehetséges jelölőként szolgálhat, amikor egy tevékenység várakozási műveletbe lép.