@@ -8,55 +8,61 @@ public class Example
88{
99 public static async Task Main ( )
1010 {
11- var tokenSource = new CancellationTokenSource ( ) ;
11+ // Cancellation token source for cancellation. Make sure to dispose after use (which is done here through the using expression).
12+ using var tokenSource = new CancellationTokenSource ( ) ;
13+
14+ // The cancellation token will be used to communicate cancellation to tasks
1215 var token = tokenSource . Token ;
1316
17+ Console . WriteLine ( "Main: Press any key to begin tasks..." ) ;
18+ Console . ReadKey ( true ) ;
19+ Console . WriteLine ( "Main: To terminate the example, press 'c' to cancel and exit..." ) ;
20+ Console . WriteLine ( ) ;
21+
1422 // Store references to the tasks so that we can wait on them and
1523 // observe their status after cancellation.
16- Task t ;
1724 var tasks = new ConcurrentBag < Task > ( ) ;
1825
19- Console . WriteLine ( "Press any key to begin tasks..." ) ;
20- Console . ReadKey ( true ) ;
21- Console . WriteLine ( "To terminate the example, press 'c' to cancel and exit..." ) ;
22- Console . WriteLine ( ) ;
26+ // Pass the token to the user delegate so it can cancel during execution,
27+ // and also to the task so it can cancel before execution starts.
28+ var cancellableTask = Task . Run ( ( ) => {
29+ DoSomeWork ( token ) ;
30+ Console . WriteLine ( "Cancellable: Task {0} ran to completion" , Task . CurrentId ) ;
31+ } , token ) ;
32+ Console . WriteLine ( "Main: Cancellable Task {0} created" , cancellableTask . Id ) ;
33+ tasks . Add ( cancellableTask ) ;
2334
24- // Request cancellation of a single task when the token source is canceled.
25- // Pass the token to the user delegate, and also to the task so it can
26- // handle the exception correctly.
27- t = Task . Run ( ( ) => DoSomeWork ( token ) , token ) ;
28- Console . WriteLine ( "Task {0} executing" , t . Id ) ;
29- tasks . Add ( t ) ;
30-
31- // Request cancellation of a task and its children. Note the token is passed
32- // to (1) the user delegate and (2) as the second argument to Task.Run, so
33- // that the task instance can correctly handle the OperationCanceledException.
34- t = Task . Run ( ( ) =>
35+ var parentTask = Task . Run ( ( ) =>
3536 {
36- // Create some cancelable child tasks.
37- Task tc ;
38- for ( int i = 3 ; i <= 10 ; i ++ )
37+ for ( int i = 0 ; i <= 7 ; i ++ )
3938 {
39+ // If cancellation was requested we don't need to start any more
40+ // child tasks (that would immediately cancel) => break out of loop
41+ if ( token . IsCancellationRequested ) break ;
42+
4043 // For each child task, pass the same token
4144 // to each user delegate and to Task.Run.
42- tc = Task . Run ( ( ) => DoSomeWork ( token ) , token ) ;
43- Console . WriteLine ( "Task {0} executing" , tc . Id ) ;
44- tasks . Add ( tc ) ;
45- // Pass the same token again to do work on the parent task.
46- // All will be signaled by the call to tokenSource.Cancel below.
47- DoSomeWork ( token ) ;
45+ var childTask = Task . Run ( ( ) => {
46+ DoSomeWork ( token ) ;
47+ Console . WriteLine ( "Child: Task {0} ran to completion" , Task . CurrentId ) ;
48+ } , token ) ;
49+ Console . WriteLine ( "Parent: Task {0} created" , childTask . Id ) ;
50+ tasks . Add ( childTask ) ;
51+
52+ DoSomeWork ( token , maxIterations : 1 ) ;
4853 }
49- } , token ) ;
5054
51- Console . WriteLine ( "Task {0} executing" , t . Id ) ;
52- tasks . Add ( t ) ;
55+ Console . WriteLine ( "Parent: Task {0} ran to completion" , Task . CurrentId ) ;
56+ } , token ) ;
57+ Console . WriteLine ( "Main: Parent Task {0} created" , parentTask . Id ) ;
58+ tasks . Add ( parentTask ) ;
5359
5460 // Request cancellation from the UI thread.
5561 char ch = Console . ReadKey ( ) . KeyChar ;
5662 if ( ch == 'c' || ch == 'C' )
5763 {
5864 tokenSource . Cancel ( ) ;
59- Console . WriteLine ( "\n Task cancellation requested." ) ;
65+ Console . WriteLine ( "\n Main: Task cancellation requested." ) ;
6066
6167 // Optional: Observe the change in the Status property on the task.
6268 // It is not necessary to wait on tasks that have canceled. However,
@@ -68,34 +74,30 @@ public static async Task Main()
6874
6975 try
7076 {
71- await Task . WhenAll ( tasks . ToArray ( ) ) ;
77+ // Wait for all tasks before disposing the cancellation token source
78+ await Task . WhenAll ( tasks ) ;
7279 }
7380 catch ( OperationCanceledException )
7481 {
75- Console . WriteLine ( $ "\n { nameof ( OperationCanceledException ) } thrown\n ") ;
76- }
77- finally
78- {
79- tokenSource . Dispose ( ) ;
82+ Console . WriteLine ( $ "\n Main: { nameof ( OperationCanceledException ) } thrown\n ") ;
8083 }
8184
8285 // Display status of all tasks.
8386 foreach ( var task in tasks )
84- Console . WriteLine ( "Task {0} status is now {1}" , task . Id , task . Status ) ;
87+ {
88+ Console . WriteLine ( "Main: Task {0} status is now {1}" , task . Id , task . Status ) ;
89+ }
8590 }
8691
87- static void DoSomeWork ( CancellationToken ct )
92+ static void DoSomeWork ( CancellationToken ct , int maxIterations = 10 )
8893 {
8994 // Was cancellation already requested?
9095 if ( ct . IsCancellationRequested )
9196 {
92- Console . WriteLine ( "Task {0} was cancelled before it got started." ,
93- Task . CurrentId ) ;
97+ Console . WriteLine ( "Task {0} was cancelled before it got started." , Task . CurrentId ) ;
9498 ct . ThrowIfCancellationRequested ( ) ;
9599 }
96100
97- int maxIterations = 100 ;
98-
99101 // NOTE!!! A "TaskCanceledException was unhandled
100102 // by user code" error will be raised here if "Just My Code"
101103 // is enabled on your computer. On Express editions JMC is
@@ -110,37 +112,49 @@ static void DoSomeWork(CancellationToken ct)
110112
111113 if ( ct . IsCancellationRequested )
112114 {
113- Console . WriteLine ( "Task {0} cancelled" , Task . CurrentId ) ;
115+ Console . WriteLine ( "Task {0} work cancelled" , Task . CurrentId ) ;
114116 ct . ThrowIfCancellationRequested ( ) ;
115117 }
116118 }
117119 }
118120}
119121// The example displays output like the following:
120- // Press any key to begin tasks...
121- // To terminate the example, press 'c' to cancel and exit...
122+ // Main: Press any key to begin tasks...
123+ // Main: To terminate the example, press 'c' to cancel and exit...
122124//
123- // Task 1 executing
124- // Task 2 executing
125- // Task 3 executing
126- // Task 4 executing
127- // Task 5 executing
128- // Task 6 executing
129- // Task 7 executing
130- // Task 8 executing
125+ // Main: Cancellable Task 13 created
126+ // Main: Parent Task 14 created
127+ // Parent: Task 15 created
128+ // Parent: Task 16 created
129+ // Parent: Task 17 created
130+ // Parent: Task 18 created
131+ // Parent: Task 19 created
132+ // Parent: Task 20 created
133+ // Cancellable: Task 13 ran to completion
134+ // Child: Task 15 ran to completion
135+ // Parent: Task 21 created
136+ // Child: Task 16 ran to completion
137+ // Parent: Task 22 created
138+ // Child: Task 17 ran to completion
131139// c
132- // Task cancellation requested.
133- // Task 2 cancelled
134- // Task 7 cancelled
140+ // Main: Task cancellation requested.
141+ // Task 20 work cancelled
142+ // Task 21 work cancelled
143+ // Task 22 work cancelled
144+ // Task 18 work cancelled
145+ // Task 14 work cancelled
146+ // Task 19 work cancelled
135147//
136- // OperationCanceledException thrown
148+ // Main: OperationCanceledException thrown
137149//
138- // Task 2 status is now Canceled
139- // Task 1 status is now RanToCompletion
140- // Task 8 status is now Canceled
141- // Task 7 status is now Canceled
142- // Task 6 status is now RanToCompletion
143- // Task 5 status is now RanToCompletion
144- // Task 4 status is now RanToCompletion
145- // Task 3 status is now RanToCompletion
150+ // Main: Task 22 status is now Canceled
151+ // Main: Task 21 status is now Canceled
152+ // Main: Task 20 status is now Canceled
153+ // Main: Task 19 status is now Canceled
154+ // Main: Task 18 status is now Canceled
155+ // Main: Task 17 status is now RanToCompletion
156+ // Main: Task 16 status is now RanToCompletion
157+ // Main: Task 15 status is now RanToCompletion
158+ // Main: Task 14 status is now Canceled
159+ // Main: Task 13 status is now RanToCompletion
146160// </Snippet04>
0 commit comments