Alternative for Thread.Sleep() to temporarily suspend program - c#

See the code at the bottom of this post. It's supposed to add "3" to the listbox, then "2" a second later, then "1" a second later and then run the main code of the program. However, once I execute the program it just stays blank 3 seconds long, after which all 3, 2, and 1 are shown, after which all the code directly starts. I want to visually see every number show up with a one second delay. How do I do this?
private void Main()
{
countdown();
//Main Code
}
private void countdown()
{
listBox1.Items.Clear();
listBox1.Items.Add("3");
System.Threading.Thread.Sleep(1000);
listBox1.Items.Add("2");
System.Threading.Thread.Sleep(1000);
listBox1.Items.Add("1");
System.Threading.Thread.Sleep(1000);
listBox1.Items.Clear();
}

async / await to the rescue:
private async void OnButtonClick(object sender, EventArgs e)
{
listBox1.Items.Clear();
listBox1.Items.Add("3");
await Task.Delay(1000);
listBox1.Items.Add("2");
await Task.Delay(1000);
listBox1.Items.Add("1");
await Task.Delay(1000);
listBox1.Items.Clear();
}

First: Why isn't anything happening?
The reason is, that you are currently in the UI thread. By doing Thread.Sleep you suspend the very same thread you expect to draw the items you just added.
Second: How to work around this?
As #CodeCaster mentioned, you could use a Timer to do all this. You could also put your code in a Thread and call the Add method by using a Dispatcher or the SynchronizationContext class and it's Send method.
Third: A small hint on the Sleep method.
Usually it should do what you expect it to, but there is no guarantee for that. Calling Sleep means that your thread will be suspended for roughly the amount of time you want it to. See this answer

You can use a Timer having the interval set to 1000. Start the timer when you want it to raise Tick event. Stop it to stop raising Tick event. Handle the Tick event and run the code in intervals.
But to have a countdown 3-2-1 function using async-await as it's suggested in the other answer is good idea:
private async void countdown()
{
listBox1.Items.Clear();
listBox1.Items.Add("3");
await Task.Delay(1000);
listBox1.Items.Add("2");
await Task.Delay(1000);
listBox1.Items.Add("1");
await Task.Delay(1000);
listBox1.Items.Clear();
}

Put a listBox1.Refresh(); after every Sleep() call.
You are letting the thread sleep, but the UI does not get repainted automagically.

Related

C# background worker frozen the GUI

I'm trying to use background worker to update a text label continuously, but for DoWork, if no loop used, it will only execute once, but if infinite loop is used, it freezes the GUI, any idea to solve this? Really appreciate!!! I'm pretty new to C# and still trying to learn.
Here's my code:
This in the main form:
backgroundWorkerX.DoWork += backgroundWorkerX_DoWork;
backgroundWorkerX.ProgressChanged += backgroundWorkerX_ProgressChanged;
backgroundWorkerX.WorkerReportsProgress = true;
backgroundWorkerX.RunWorkerAsync();
Then:
public void backgroundWorkerX_DoWork(object sender, DoWorkEventArgs e)
{
X = -(RSSI_PI1_ST1);
backgroundWorkerX.ReportProgress(X);
}
public void backgroundWorkerX_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
label9.Text = e.ProgressPercentage.ToString();
}
public void backgroundWorkerX_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
}
[...] if no loop used, it will only execute once
This is the expected behavior. It will do the thing it's expected and then call RunWorkerCompleted.
[...] but if infinite loop is used, it freezes the GUI.
You don't present a loop in your question. So I'll make an assumption and will give you an educated guess that it actually consumes all the CPU, and therefore crashes the GUI.
// I assume that you loop like this somehow.
do
{
X = -(RSSI_PI1_ST1);
backgroundWorkerX.ReportProgress(X);
} while (true);
Try to add something to "slow it down" once in a while. Otherwise it will just run and run as fast as possible, and therefore consume all the CPU available. Remember that everytime you use ReportProgress it will be rendered by the GUI-thread. And this will execute very often and not leave a lot of resources for the GUI thread to respond to other things. Below I use Thread.Sleep, which will pause the thread for half a second. But remember that you will only want to do this in a background thread.
do
{
X = -(RSSI_PI1_ST1);
backgroundWorkerX.ReportProgress(X);
Thread.Sleep(500);
} while (true);
I would also consider doing this another way. If you actually have the need of pausing the thread, you might as well do it with a Timer. Thread.Sleep will lock the thread, and may therefore not be what you really want. From this answer:
Process() // method to be called after regular interval in Timer
{
// lengthy process, i.e. data fetching and processing etc.
// here comes the UI update part
Dispatcher.Invoke((Action)delegate() { /* update UI */ });
}

Reconnect to server in 5 seconds c# (Task) [duplicate]

Hi I am trying to find a method of waiting a number of milliseconds before moving to the next line of code,
I have looked into Thread.Sleep but this will freeze the main form, I would like this to remain active.
I tried timers and stopwatches and both freeze the main form when they should be posting to a console when they tick.
I couldn't find a way of using task.delay or background worker in the wait I wanted either.
Pseudo Code:
Wait 2 - 6 seconds
Log "waiting"
Log "waiting"
Log "waiting"
Stop Waiting - Run next line of code.
The methods I have tried just freeze up the form and fill the log afterwards, I just want a simple method of waiting without freezing the form and without having to deal with events being called which would mean the next line isn't run.
Any help would be awesome because I am still new to c# and its been driving me a bit mad :(
The await keyword, in conjunction with Task.Delay makes this trivial.
public async Task Foo()
{
await Task.Delay(2000);
txtConsole.AppendText("Waiting...");
DoStuff();
}
Try using a DispatcherTimer. It's a pretty handy object that does all the work of delegating to the UI thread.
For example:
private DispatcherTimer _dtTimer = null;
public Constructor1(){
_dtTimer = new DispatcherTimer();
_dtTimer.Tick += new System.EventHandler(HandleTick);
_dtTimer.Interval = new TimeSpan(0, 0, 0, 2); //Timespan of 2 seconds
_dtTimer.Start();
}
private void HandleTick(object sender, System.EventArgs e) {
_uiTextBlock.Text = "Timer ticked!";
}
Timer should work fine in this case, unless you put Thread.Sleep in its handler or the handler itself takes too much time to complete.
You haven't specified the UI framework that you use or .Net version, but for the latest .Net you can use async/await. That way, UI would not be frozen while your code awaits for the background task
void async MyMethod()
{
var result = await Task.Run(() => long_running_code);
}
DateTime Tthen = DateTime.Now;
do
{
Application.DoEvents();
} while (Tthen.AddSeconds(5) > DateTime.Now);

foreach async sleep method

I am trying to make my foreach loop asynchronous. The loop loops the first time, does something then it will wait 40 seconds and then the loop loops again does something, waits 40 seconds etc...
In my situation I am looping around tweets, getting the tweet user name and then sending a tweet to them.
I tried using the Thread.Sleep(40000) method but that just freezes the app and I can't use it, and the loop doesn't stop for 40 seconds and then loops again. The app freezes but the loop doesn't, the tweets are getting sent without even waiting at all. This how my code looks like
private void tweetButton_Click(object sender, EventArgs e)
{
var tweets= .........
foreach (var tweet in tweets)
{
// Do Something
System.Threading.Thread.Sleep(40000);
}
How would I let the foreach loop to pause before looping again on its self, and how would I make it pause without freezing my application?
https://msdn.microsoft.com/en-us/library/hh194873(v=vs.110).aspx
I think you can await Task.Delay(40000); - to me that would be an 'async sleep' like you've asked for.
Alternatively, you could kick off a timer. The timer is probably a better choice, but will run on a threadpool thread.
EDIT: Not sure why this got -1...but if anyone has an explanation, I'd be interested.
I've verified that 'await Task.Delay(xyz)' does work for this purpose. Naturally, you'd need the async keyword to be added.
static async void DoSomething()
{
for(var i = 0;i<25;i++)
{
// Do Something
await Task.Delay(1000);
Console.WriteLine("Sending a Tweet");
}
}
I can't speak to the performance, but it seems to work fine for me.
You want your code to run on a different thread, so it doens note impede the code running in your winforms gui thread.
The best way for you specific needs is a timer that you kickoff once and that then does your job.
{
Timer t = new Timer();
t.Interval = 50000;
t.Elapsed += T_Elapsed;
t.Start();
}
private static void T_Elapsed(object sender, ElapsedEventArgs e)
{
}
If you need to access your winforms controls from here, you can use invoke, so the commands are placed into the the gui threads message loop.
control.Invoke((MethodInvoker)(() =>
{
//Do your thing
}));
You could implement background process in form. That would works in your case.

Using Timer to measure Parallel.ForEach progress pauses unexpectedly

I'm using Parallel.ForEach for the first time, where I'm processing files; in the context of a WinForms app.
As per guidance from other threads on this coding problem (Parallel.ForEach progress reporting) I have a public (int) counter property on my class which contains the parallel code, and it's successfully updating; I also have a Timer on my Form that periodically reads the counter.
The issue is that when I execute the parallel code the visible progress updating appears to stop, and then starts as soon as the parallel code is complete.
FYI - I'm calling the parallel code directly - that is, not through a background worker or async method.
Parallel.ForEach actually evaluates the query in parallel fashion but does wait for finishing of execution and blocks the calling thread.
You should use it on a separate thread/backgroundworker/task to get your progress variable updating while not blocking the UI.
If you are calling Parallel.ForEach() from your UI thread (lacking a code example, there's no way for us to know for sure what's happening), then the fact that that method stops and waits for all the processing to complete will prevent your UI thread from doing any other work, including a) allowing the timer event from being processed, and b) allowing the UI to be updated even if the timer even were processed.
One possible approach would be to wrap the call of Parallel.ForEach() in a call to Task.Run(). For example:
private async void button1_Click(object sender, EventArgs e)
{
// some stuff
await Task.Run(() => Parallel.ForEach(...));
// some other stuff
}
Alternatively, you could just execute the whole thing as individual tasks:
private async void button1_Click(object sender, EventArgs e)
{
// some stuff
List<Task> tasks = new List<Task>();
foreach (...)
{
tasks.Add(Task.Run(() => ...));
}
await Task.WhenAll(tasks);
// some other stuff
}
(The above examples leave out specifics, since without a code example in the question there's no way to know what would actually go there).
Either approach should free up your UI thread to handle the progress updating while the processing goes on.

Awaken a task while sleeping

I have a task that runs periodically 10 second. I do some picturebox refreshing processes by reading database. What i want is to invoke or awaken the thread and do the refresh operation when i click a button immidiately. In short, i want the refresh task to be driven by not only time but also event together. Is this possible? If yes, how? The code block for the task is shown below.
while (true)
{
// do some refresh operation
Thread.Sleep(10000);
}
void button1_Click(object sender, EventArgs e)
{
// invoke or awaken thread
}
First off I'd advise you to drop the Thread + Sleep + Invoke combo for timed operations. It's very ugly. There are timer classes for both WinForms and WPF to do these three things automatically (update the GUI periodically from the dispatcher thread). Check out System.Windows.Forms.Timer and System.Windows.Threading.DispatcherTimer.
Now for your specific question, you could simply define a common method for updating the GUI with what you need and call it both from the timer code and from a button handler.
Create an AutoResetEvent:
protected AutoResetEvent _threadCycle;
_threadCycle = new AutoResetEvent(false);
when you want to wait do:
_threadCycle.WaitOne(delay, false);
and when you want to set the event, effectually letting the thread to continue:
_threadCycle.Set();
BONUS:
when you do _threadCycle.WaitOne(delay, false); you will get a return value, true or false, that you can check to see if the timeout did expire or you are continuing because of the manually set event.
BTW:
that will ONLY work if you are doing your task in an alternate thread. If you use main thread, you will get stuck with waiting for the timeout completion anyway. Maybe it will be the best to use #Tudors answer, and get this option only as 'through the thorns' way.
You should use a AutoResetEvent for this.
What you do is something like (assuming your AutoResetEvent is called 'signal'):
while (true)
{
signal.WaitOne(10000);
...
}
And in your button handler, just do:
signal.Set();

Categories

Resources