Why wait is not coming back?

I see an expectation that seems to never return. Here is an example code:

public partial class MainWindow : Window, INotifyPropertyChanged { private string _status; private CancellationTokenSource _cancellationTokenSource; public MainWindow() { InitializeComponent(); _status = "Ready"; DataContext = this; } public string Status { get { return _status; } set { _status = value; OnPropertyChanged(nameof(Status)); } } private void OnStart(object sender, RoutedEventArgs e) { Status = "Running..."; _cancellationTokenSource = new CancellationTokenSource(); StartProcessing(); } private void OnStop(object sender, RoutedEventArgs e) { _cancellationTokenSource.Cancel(); } private async void StartProcessing() { try { await new Task(() => { Thread.Sleep(5000); }, _cancellationTokenSource.Token); } catch (TaskCanceledException e) { Debug.WriteLine($"Expected: {e.Message}"); } Status = "Done!"; } public event PropertyChangedEventHandler PropertyChanged; protected virtual void OnPropertyChanged(string propertyName) { PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); } } 

What happens when OnStart is called, it sets the status to "Run ...", then calls StartProcessing. Five seconds have passed, but I never see the status set to "Done!"

If I call OnStop, the task is canceled and I see "Finish!". status.

I assume I am creating a task, as well as a task created by async / await, but does it hang or come to a standstill?

Here's the WPF XAML code:

 <Window x:Class="CancellationSample.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="d" Title="Cancellation Test" Height="350" Width="525"> <DockPanel LastChildFill="True"> <StackPanel DockPanel.Dock="Top"> <Button Width="70" Margin="5" Click="OnStart">Start</Button> <Button Width="70" Margin="5" Click="OnStop">Stop</Button> </StackPanel> <StatusBar DockPanel.Dock="Bottom"> <StatusBarItem> <TextBlock Text="{Binding Status}"/> </StatusBarItem> </StatusBar> <Grid></Grid> </DockPanel> </Window> 
+5
source share
2 answers

You create a new Task , but do not start it, so it never ends. Use Task.Run and await instead .

 await Task.Run(() => { }); 

Consider also Task.Delay instead of Thread.Sleep so that you do not block the current thread,

+6
source

You want to avoid using async void methods. Update StartProcessing to return Task , and you should also use Task.Delay instead of Task.Delay

 private async Task StartProcessing() { try { await Task.Delay(5000, _cancellationTokenSource.Token); } catch (TaskCanceledException e) { Debug.WriteLine($"Expected: {e.Message}"); } Status = "Done!"; } 

Further, if OnStart is actually an event handler, this is the only exception where async void allowed. Update OnStart for asynchronization, and then wait for the expected StartProcessing

 private async void OnStart(object sender, RoutedEventArgs e) { Status = "Running..."; _cancellationTokenSource = new CancellationTokenSource(); await StartProcessing(); } 

Finally, I would suggest reading

Async / Await - Best Practices in Asynchronous Programming by Stephen Cleary

to better understand how to use async / await

+5
source

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


All Articles