Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Keeping UI responsive during a Thread.Sleep() [duplicate]

Background: I am writing an application that iterates through a list of servers and obtains various details about each machine. During the iteration, I need to update various controls on the form (to display a summary of the obtained information). Because it is iterating through a list, I have called a Thread.Sleep() to allow the user time to read through the information before the next machine is interrogated. Below is my code:

Task TestTask = Task.Factory.StartNew(() =>
            {
                foreach (String IpAddress in ServersToCheck)
                {
                    if (IpAddress != String.Empty)
                    {
                        ServerBeingCheckedLabel.Text = IpAddress;
                        if (PingServer(IpAddress) == true)
                        {
                            PingChar_Label.ForeColor = Color.Green;
                            PingChar_Label.Text = "a";
                            CheckPermissionsAreValid(IpAddress);
                        }
                        else
                        {
                            PingChar_Label.ForeColor = Color.Red;
                            PingChar_Label.Text = "r";
                            PermChar_Label.ForeColor = Color.Red;
                            PermChar_Label.Text = "r";
                        }
                    }
                }
                Thread.Sleep(10000);
                this.BackColor = FormBackGroundColor;
                TestButton.Enabled = true;
                RunTimer.Enabled = true;
            }, CancellationToken.None, TaskCreationOptions.None, UiScheduler);

This works fine regarding updating the controls on the form, but during the Thread.Sleep() the UI locks up. Surely if the Thread.Sleep() is called on a separate task, the UI thread has remained unblocked?

like image 990
Chris Wright Avatar asked Dec 19 '22 01:12

Chris Wright


2 Answers

Task.Delay should suit your needs.

Change

Task.Factory.StartNew(() =>

to

Task.Factory.StartNew(async () =>

and change

Thread.Sleep

to

await Task.Delay
like image 121
Dante May Code Avatar answered Jan 06 '23 20:01

Dante May Code


If you pass the UiScheduler as TaskScheduler then that task is running on the UI thread. So yes, the UI thread is completely blocked when you call Thread.Sleep.

If you want to delay use await Task.Delay(10000) instead to delay asynchronously.

That will make the task returned from Task.Factory.StartNew a Task<Task> because it wasn't build with async-await in mind unlike Task.Run. To fix that use Task.Unwrap on the returned Task:

Task<Task> TestTask = Task.Factory.StartNew(async () =>
{
    // ...
    await Task.Delay(10000);
    // ...
}, CancellationToken.None, TaskCreationOptions.None, UiScheduler);

Task actualTask = TestTask.Unwrap();
like image 26
i3arnon Avatar answered Jan 06 '23 18:01

i3arnon