Why these two C# code blocks about Task behaves differently?

I am studying C# Task, async/await and I have encountered a situation that I do not quite understand. I made two code snippet, the first one is based upon console application, and the second one is based upon wpf. Here are the two code snippet:

  1. code for console application:
async static Task Main()
{
    Helper.PrintThreadId("Before");
    await FooAsync();
    Helper.PrintThreadId("After");
}

async static Task FooAsync()
{
    Helper.PrintThreadId("Before");
    await Task.Delay(1000);
    Helper.PrintThreadId("After");
}

class Helper
{
    private static int index = 1;
    public static void PrintThreadId(string message = null, [CallerMemberName] string name = null)
    {
        var title = $"{index}: {name}";
        if (!string.IsNullOrEmpty(message))
            title += $" @ {message}";
        Console.WriteLine("Thread ID: " + Environment.CurrentManagedThreadId + ", title: " + title);
        Interlocked.Increment(ref index);
    }
}
  1. code for wpf (Helper is exactly same as in console application):
async Task<int> HeavyJob()
{
    Helper.PrintThreadId("Before");
    await Task.Delay(3000);
    Helper.PrintThreadId("After");
    return 10;
}

private async void Button_Click(object sender, RoutedEventArgs e)
{
    Helper.PrintThreadId("Before");
    var res = await HeavyJob().ConfigureAwait(false);
    Helper.PrintThreadId("After");
}

class Helper
{
    private static int index = 1;
    public static void PrintThreadId(string message = null, [CallerMemberName] string name = null)
    {
        var title = $"{index}: {name}";
        if (!string.IsNullOrEmpty(message))
            title += $" @ {message}";
        Debug.WriteLine("Thread ID: " + Environment.CurrentManagedThreadId + ", title: " + title);
        Interlocked.Increment(ref index);
    }
}

Then, for console application, the result is:

for wpf, the result is:

My question is the third line of the two results. why these two behaves differently? As I understand, the thread ID in the third line and fourth line should be the same.

I hope if anyone could explain this question. Thank you.

3

In the WPF code in HeavyJob() you have this:

await Task.Delay(3000);

That does not have .ConfigureAwait(false) so for a WPF (or WinForms) application it will resume on the same thread that it was started on – that will be thread 1 in your example. It can do this because the SynchronizationContext has the ability to use the Windows message loop to resume on the UI thread.

Similarly in the console code in FooAsync() you also have an await without .ConfigureAwait(false). However, for console apps by default there is no SynchronizationContext available to use to resume on the calling thread. So in this case the await resumes on a new thread.

2

When you await a task, there is actually no guarantee the code that follows gets scheduled to a different thread. Rather, SynchronizationContext.Current is used to determine where the continuation should be executed.

For WPF/WinForms applications, there is a main loop that handles all events, including scheduled tasks. In such a context, awaiting a task is able to resume the code on the original thread. This is important because the controls are not thread-safe; they should be accessed only from the main thread. This is the reason you see HeavyJob @ After resumed on the same thread.

In console applications, there is no main loop and no need to keep the bulk of the code single-threaded. Hence continuations are executed on various other threads (for example from the thread pool), since there is no way to return back to the original thread.

Now with this explanation, you would expect all code after await to run on the same thread on WPF, but this is actually not the case here. The reason is that you used .ConfigureAwait(false) ‒ this specifically instructs the awaiter not to use the original synchronization context, reverting back to the default behaviour you see in case of the console application. I’d argue this is actually not a good place to use ConfigureAwait(false) ‒ I’d stick to the normal behaviour for GUI event handlers, since you are expected to work with GUI controls, and use .ConfigureAwait(false) in the inner logic where resuming on the same thread is no longer necessary (once you don’t have any more controls to work with).

0

Trang chủ Giới thiệu Sinh nhật bé trai Sinh nhật bé gái Tổ chức sự kiện Biểu diễn giải trí Dịch vụ khác Trang trí tiệc cưới Tổ chức khai trương Tư vấn dịch vụ Thư viện ảnh Tin tức - sự kiện Liên hệ Chú hề sinh nhật Trang trí YEAR END PARTY công ty Trang trí tất niên cuối năm Trang trí tất niên xu hướng mới nhất Trang trí sinh nhật bé trai Hải Đăng Trang trí sinh nhật bé Khánh Vân Trang trí sinh nhật Bích Ngân Trang trí sinh nhật bé Thanh Trang Thuê ông già Noel phát quà Biểu diễn xiếc khỉ Xiếc quay đĩa Dịch vụ tổ chức sự kiện 5 sao Thông tin về chúng tôi Dịch vụ sinh nhật bé trai Dịch vụ sinh nhật bé gái Sự kiện trọn gói Các tiết mục giải trí Dịch vụ bổ trợ Tiệc cưới sang trọng Dịch vụ khai trương Tư vấn tổ chức sự kiện Hình ảnh sự kiện Cập nhật tin tức Liên hệ ngay Thuê chú hề chuyên nghiệp Tiệc tất niên cho công ty Trang trí tiệc cuối năm Tiệc tất niên độc đáo Sinh nhật bé Hải Đăng Sinh nhật đáng yêu bé Khánh Vân Sinh nhật sang trọng Bích Ngân Tiệc sinh nhật bé Thanh Trang Dịch vụ ông già Noel Xiếc thú vui nhộn Biểu diễn xiếc quay đĩa Dịch vụ tổ chức tiệc uy tín Khám phá dịch vụ của chúng tôi Tiệc sinh nhật cho bé trai Trang trí tiệc cho bé gái Gói sự kiện chuyên nghiệp Chương trình giải trí hấp dẫn Dịch vụ hỗ trợ sự kiện Trang trí tiệc cưới đẹp Khởi đầu thành công với khai trương Chuyên gia tư vấn sự kiện Xem ảnh các sự kiện đẹp Tin mới về sự kiện Kết nối với đội ngũ chuyên gia Chú hề vui nhộn cho tiệc sinh nhật Ý tưởng tiệc cuối năm Tất niên độc đáo Trang trí tiệc hiện đại Tổ chức sinh nhật cho Hải Đăng Sinh nhật độc quyền Khánh Vân Phong cách tiệc Bích Ngân Trang trí tiệc bé Thanh Trang Thuê dịch vụ ông già Noel chuyên nghiệp Xem xiếc khỉ đặc sắc Xiếc quay đĩa thú vị
Trang chủ Giới thiệu Sinh nhật bé trai Sinh nhật bé gái Tổ chức sự kiện Biểu diễn giải trí Dịch vụ khác Trang trí tiệc cưới Tổ chức khai trương Tư vấn dịch vụ Thư viện ảnh Tin tức - sự kiện Liên hệ Chú hề sinh nhật Trang trí YEAR END PARTY công ty Trang trí tất niên cuối năm Trang trí tất niên xu hướng mới nhất Trang trí sinh nhật bé trai Hải Đăng Trang trí sinh nhật bé Khánh Vân Trang trí sinh nhật Bích Ngân Trang trí sinh nhật bé Thanh Trang Thuê ông già Noel phát quà Biểu diễn xiếc khỉ Xiếc quay đĩa
Thiết kế website Thiết kế website Thiết kế website Cách kháng tài khoản quảng cáo Mua bán Fanpage Facebook Dịch vụ SEO Tổ chức sinh nhật