locked
async await randomly loosing SynchronizationContext RRS feed

  • Question

  • Hello,

    we are experiencing issues with the following sample program.

    If we use await the sample is loosing the SynchronizationContext immediately within the new Task. TaskCreationOptions make no difference at all for this kind of behavior. If we switch to .Wait() instead the Synchronization context is set within the first task and some of the other subtasks. It seems like it is getting ignored after a certiain amount of time. Adding timeconsuming code enforces the SynchronizationContext to get lost earlier within the loop.

    Is this some kind of intended behavior or are we simply doing something wrong?

    class Program
        {
            static void Main(string[] args)
            {
                new Test().TestMethod().Wait();
                Console.ReadKey();
            }
        }
    
        public class Test
        {
            private static SynchronizationContext _syncContext = new SynchronizationContext();
            public async Task TestMethod()
            {            
                SynchronizationContext.SetSynchronizationContext(_syncContext);
                CallContext.LogicalSetData("test", "1");
                Console.WriteLine($"-1 |C {CallContext.LogicalGetData("test")}");
                Console.WriteLine($"-1 |E {ExecutionContext.Capture().GetHashCode().ToString("D")}");
                Console.WriteLine($"-1 |S {SynchronizationContext.Current.GetHashCode().ToString("D")}");
                var mainTask = new TaskFactory().StartNew(() =>
                {
                    Console.WriteLine($"0 |C {CallContext.LogicalGetData("test")}");
                    Console.WriteLine($"0 |E {ExecutionContext.Capture().GetHashCode().ToString("D")}");
                    Console.WriteLine($"0 |S {SynchronizationContext.Current.GetHashCode().ToString("D")}");
                    var tasks = new List<Task>();
                    int j = 0;
                    for (int i = 0; i < 10; i++)
                    {
                        var task =
                            new TaskFactory().StartNew(
                                () =>
                                {
                                    j++;
                                    Console.WriteLine($"{j} |C {CallContext.LogicalGetData("test")}");
                                    Console.WriteLine($"{j} |E {ExecutionContext.Capture().GetHashCode().ToString("D")}");
                                    try
                                    {
                                        Console.WriteLine($"{j} |S {SynchronizationContext.Current.GetHashCode().ToString("D")}");
                                    }
                                    catch (Exception exception)
                                    {
                                        Console.WriteLine($"{j} |S Lost");
                                    }
                                },
                                new CancellationToken(),
                                TaskCreationOptions.LongRunning | TaskCreationOptions.AttachedToParent,
                                TaskScheduler.FromCurrentSynchronizationContext());
                        task.ConfigureAwait(false).GetAwaiter().GetResult();
                        //task.Wait();
                        tasks.Add(task);
                    }
                    //Task.WaitAll(tasks.ToArray());
                    Console.WriteLine($"11 |C {CallContext.LogicalGetData("test")}");
                    Console.WriteLine($"11 |E {ExecutionContext.Capture().GetHashCode().ToString("D")}");
                    Console.WriteLine($"11 |S {SynchronizationContext.Current.GetHashCode().ToString("D")}");
                }, new CancellationToken(), TaskCreationOptions.LongRunning | TaskCreationOptions.AttachedToParent,
                    TaskScheduler.FromCurrentSynchronizationContext());
                await mainTask.ConfigureAwait(false);
                //mainTask.Wait();
            }
        }

    Wednesday, November 11, 2015 8:55 AM

All replies

  • I'm a bit new to TPL.. But remember reading a few things regarding taskfactory in a .NET Test Exam. Have you tried something like.. 

    mainTask.WaitAll(tasks);
    It should keep all tasks synchronized.. but you'll have to test the results of course.

    Wednesday, November 11, 2015 1:45 PM
  • What you are talking about is this line

    //Task.WaitAll(tasks.ToArray());
    the task instance itself doesn't have a WaitAll. If you run the sample you will experience a completely different behavior for the Wait() or WaitAll(tasks.ToArray()) compared to using the await. This is because of the way how it gets compiled. It seems like the sate machine which is getting added for the await is a bit different compared to the Wait().

    But beside that both versions won't work as I expected them to work. Imo the synchronization context should get copied.


    Thursday, November 12, 2015 7:07 AM