I was following an example from C# in a Nutshell. According to the text the following code is supposed to be non blocking, but I find that the form will not display until the 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 it's something to do with Thread.Sleep() and instead of putting the new Thread to sleep, it's putting the main Thread to sleep.
Why is it blocking the UI thread?
User Interface Thread or UI-Thread in Android is a Thread element responsible for updating the layout elements of the application implicitly or explicitly. This means, to update an element or change its attributes in the application layout ie the front-end of the application, one can make use of the UI-Thread.
The running thread will block when it must wait for some event to occur (response to an IPC request, wait on a mutex, etc.). The blocked thread is removed from the running array, and the highest-priority ready thread that's at the head of its priority's queue is then allowed to run.
It is also almost always the thread in which your application interacts with components from the Android UI toolkit (components from the android. widget and android. view packages). As such, the main thread is also sometimes called the UI thread.
Put simply: The Main Thread is where the browser does most of the work needed to display a page. If we keep the Main Thread blocked, it can't perform its crucial tasks. This leads to slow load times, unresponsive pages, and a bad user experience.
When you are trying to get result of task task.Result main thread will be blocked until task will finish it's execution (i.e. result will be available). Use task.ContinueWith
if you don't want to wait for async operation completion:
Task<int> task = tcs.Task;
task.ContinueWith(t => {
MessageBox.Show(t.Result.ToString());
});
BTW there is nice feature in .NET 4.5 for resuming suspended operation when 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 yield control to caller immediately after starting to wait for task result. When result will be available, method will continue execution and show message.
Actually as @Servy pointed in comments, async method which return void
is not very good practice (e.g. for error handling), but sometimes it's OK to use them for event handlers.
When you call Task.Result.ToString()
(in the MessageBox.Show
) the Task
class has a mechanism that waits for the task to be finished before actually giving you the result (as it doesn't actually have it until the Task
finishes. Here's my proof:
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 the 2.5sec message box before the messagebox with 42. (in fact, 2.5 seconds before that).
What you are looking for is this:
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 UI thread.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With