User interface lock

I followed the example from C # in a nutshell. According to the text, the following code should not be blocked, but I found that the form will not be displayed until after 5 seconds have passed.

private void Form1_Load(object sender, EventArgs e) { var tcs = new TaskCompletionSource<int>(); new Thread(() => {Thread.Sleep(5000); tcs.SetResult(42); }).Start(); Task<int> task = tcs.Task; MessageBox.Show(task.Result.ToString()); } 

I have a feeling this is due to Thread.Sleep () and instead of putting the new thread to sleep, it puts the main thread to sleep.

Why does it block the user interface thread?

+6
source share
2 answers

When you call Task.Result.ToString() (in MessageBox.Show ), the Task class has a mechanism that waits for the task to complete before actually giving you the result (since it actually doesn't have it until the Task ends. Here's mine evidence:

 private void Form1_Load(object sender, EventArgs e) { var tcs = new TaskCompletionSource<int>(); new Thread(() => {Thread.Sleep(5000); tcs.SetResult(42); }).Start(); Task<int> task = tcs.Task; Thread.Sleep(2500); MessageBox.Show("Waited for 2.5secs on UI thread."); MessageBox.Show(task.Result.ToString()); } 

You will see that it shows you a message with a 2.5sec message before message number 42. (in fact, 2.5 seconds before that).

What you are looking for is:

 private void Form1_Load(object sender, EventArgs e) { var tcs = new TaskCompletionSource<int>(); new Thread(() => {Thread.Sleep(5000); tcs.SetResult(42); }).Start(); Task<int> task = tcs.Task; task.ContinueWith(t => MessageBox.Show(t.Result.ToString())); } 

This will not freeze the user interface thread.

+5
source

When you try to get the result of the task.Result task, the main thread will be blocked until the task completes its execution (i.e. the result will be available). Use task.ContinueWith if you do not want to wait for the async operation to complete:

 Task<int> task = tcs.Task; task.ContinueWith(t => { MessageBox.Show(t.Result.ToString()); }); 

By the way, in .NET 4.5 there is a good function to resume a paused operation when a task is completed - async methods:

 private async void Form1_Load(object sender, EventArgs e) { var tcs = new TaskCompletionSource<int>(); new Thread(() => { Thread.Sleep(2000); tcs.SetResult(42); }).Start(); int result = await tcs.Task; MessageBox.Show(result.ToString()); } 

This method will give control to the caller immediately after the start of waiting for the result of the task. When the result is available, the method continues execution and displays a message.

In fact, as @Servy pointed out in the comments, the async method returning void is not a good practice (for example, to handle errors), but sometimes it’s normal to use it for event handlers.

+11
source

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


All Articles