Child job canceled, parent completed?

I am trying to understand the behavior of .net tasks when children are attached.

I have the following test code:

void Test() { var tokenSource = new CancellationTokenSource(); var token = tokenSource.Token; Task child = null; var parent = Task.Factory.StartNew(() => { child = Task.Factory.StartNew(() => { while (!token.IsCancellationRequested) Thread.Sleep(100); token.ThrowIfCancellationRequested(); }, token, TaskCreationOptions.AttachedToParent, TaskScheduler.Default); }, token); Thread.Sleep(500); Debug.WriteLine("State of parent before cancel is {0}", parent.Status); Debug.WriteLine("State of child before cancel is {0}", child.Status); tokenSource.Cancel(); Thread.Sleep(500); Debug.WriteLine("State of parent is {0}", parent.Status); Debug.WriteLine("State of child is {0}", child.Status); } 

Result:

 State of parent before cancel is WaitingForChildrenToComplete State of child before cancel is Running A first chance exception of type 'System.OperationCanceledException' occurred in mscorlib.dll State of parent is RanToCompletion State of child is Canceled 

Apparently, the state of the parent task is not Canceled , although both tasks share a token, and the child is attached.

How do I return the parent status of a Canceled return when a cancellation occurs?

Note If I throw an exception, then both tasks return Faulted .

+6
source share
2 answers

This is the expected behavior specified in the MSDN. The parent task must wait (scroll down to the undo section) for the child task. The parent task must handle all benign errors (e.g. invalidation).

For your parent task to fail, just wait and pass the token:

 Task child = null; var parent = Task.Factory.StartNew(() => { child = Task.Factory.StartNew(() => { while (!token.IsCancellationRequested) Thread.Sleep(100); token.ThrowIfCancellationRequested(); }, token, TaskCreationOptions.AttachedToParent, TaskScheduler.Default); // This is the magic line. child.Wait(token); }, token); 

If you use this code to create something productive and not just for testing, you should also consider using the simplified Task.Run() , which supports async delegates instead of Task.Factory.StartNew() . This article is very interesting.

+4
source

Your example is rather confusing and hides intuitive behavior, and your expectations are wrong.

Start with a working example:

 void Test() { var tokenSource = new CancellationTokenSource(); var token = tokenSource.Token; Task child = null; var parent = Task.Factory.StartNew(() => { child = Task.Factory.StartNew(() => { while (!token.IsCancellationRequested) Thread.Sleep(100); token.ThrowIfCancellationRequested(); }, token, TaskCreationOptions.AttachedToParent, TaskScheduler.Default); while (!token.IsCancellationRequested) Thread.Sleep(100); token.ThrowIfCancellationRequested(); }, token); Thread.Sleep(500); Debug.WriteLine("State of parent before cancel is {0}", parent.Status); Debug.WriteLine("State of child before cancel is {0}", child.Status); tokenSource.Cancel(); Thread.Sleep(500); Debug.WriteLine("State of parent is {0}", parent.Status); Debug.WriteLine("State of child is {0}", child.Status); } 

In order for the parent element to be canceled, you need to call somewhere in the body of the parent token.ThrowIfCancellationRequested() . However, just calling token.ThrowIfCancellationRequested() not enough.

You need to conceptualize how parent and child threads flow together to understand why your expectations are wrong.

 Main thread: ---\------------------------------------[Cancel]-----/ Parent: \---\-----[Check cancellation]------------------/ Child: \------------------------------[Cancel]---/ 

As you can see from the above diagram, the parent checks the cancellation method before the cancellation request. The child receives a cancellation signal because he basically waits for the cancellation to be canceled. Now, if you put the same mechanism in the parent, it will receive a cancel signal because it has not finished working before the cancellation is reported.

+1
source

Source: https://habr.com/ru/post/982608/


All Articles