I was using a BackgroundWorker to download some web sites by calling WebClient.DownloadString inside a loop. I wanted the option for the user to cancel in the middle of downloading stuff, so I called CancelAsync whenever I found that CancellationPending was on in the middle of the loop.
But now I noticed that the function DownloadString kinda freezes sometimes, so I decided to use DownloadStringAsync instead (all this inside the other thread created with BackgroundWorker). And since I don't want to rewrite my whole code by having to exit the loop and the function after calling DownloadStringAsync, I made a while loop right after calling it that does nothing but check for a variable bool Stop that I turn true either when the DownloadStringCompleted event handler is called or when the user request to cancel the operation.
Now, the weird thing is that it works fine on the debug version; but on the release one, the program freezes in the while loop like if it were the main thread.
Sounds to me you are busy-waiting with a while loop. You should use event signaling instead, eg. a WaitHandle. A busy-waiting loop in release mode might very well consume all your cpu, giving a feeling of a freeze.
Signal the WaitHandle in DownloadStringCompleted or if the user cancels the download.
Check the MSDN docs on the WaitHandle class. There's also an example there.
Send your while loop that is checking for the cancelation to sleep for a short while (some ms). This well free up the CPU runtime for other threads and processes.
nice topic, i used
In my background worker process a double while
int icounter = 1;
while (icounter < SomeListInventory.Count)
{
while (pauseWorker == false)
{
//-----------------------
//DO SOME WORK
icounter++;
//-----------------------
}
}
And i have a button pause, that when i press it, pauseWorker (Global variable or property) becomes true and loops in the first while only, without increasing the icounter, and when i make the pauseworker=false again the process continues
Related
I made a short program which has just a button. When the button is pressed, functionA is executed, which also uses functionB and functionC. Inside functionA is a loop which executes functionB and functionC X amount of times. At the end of each loop, the progressbar gets incremented by 1. At the beginning of functionA, before the loop, there's a webservice which pulls data from a website, and passes that onto B and C for processing (data file manipulation and saving to disk).
My problem is that everything works fine, but while functionA is still running, the GUI is stuck, so I can't close/minimize/drag the window around, I have to wait until A is done. I researched and they say I should use BackgroundWorker, but as being a new programmer, I've no idea on how to use it. Can someone give me a simple way to use it?
The progressbar loads fine, but it's just that while the function is running, the whole window is frozen, and I want it so I can move the window around, etc while the program is running, instead of waiting until the function is complete.
Thank you!
Call your function asynchronously like the following and it will not freeze the UI.
private async void BeginProcessingAsync(Data d)
{
//Execute the long running task asynchronously
await Task.Run(() => functionA(d));
//Anything after the await line will be executed only after the task is finished.
anotherFunction(d); // if you have one..
}
To run your task, simply call BeginProcessingAsync(d);. Also, please note: If you're using newer versions of .NET, you might have to use await Task.Factory.StartNew(() => functionA(d)); instead of the above
Overall, you'll want to make sure your GUI doesn't get updated from another thread. Instead, the messages should go to a threadsafe location. For instance, you could have the thread building into something like a database and have the GUI using a timer to look for updated data flags.
There is a question with a lot more detail using delegates here.
Marc's answer was the simplest and best, in my opinion:
///...blah blah updating files
string newText = "abc"; // running on worker thread
this.Invoke((MethodInvoker)delegate {
someLabel.Text = newText; // runs on UI thread
});
///...blah blah more updating files
From Dotnet Perls:
A Background Worker makes threads easy to implement in Windows
Forms. Intensive tasks need to be done on another thread so the UI
does not freeze. It is necessary to post messages and update the user
interface when the task is done.
Also, from MSDN, look at Task-based Asynchronous Pattern (TAP) if you're using C# 5.
The Task-based Asynchronous Pattern (TAP) is based on the
System.Threading.Tasks.Task and System.Threading.Tasks.Task
types in the System.Threading.Tasks namespace, which are used to
represent arbitrary asynchronous operations. TAP is the recommended
asynchronous design pattern for new development.
I have a multi-threaded application, and both in the main UI thread and in other background threads, I have stop-methods that call Application.Exit().
The weird thing is that after the call, the program continues on to the next line (and then eventually exits). The obvious problem with this can be explained with the simple code below:
if (XYZ) Application.Exit();
Globals.Instance.LoggerDictionary["ApplicationLog"].Log("Bla bla...");
And this:
private void Form1_FormClosing(object sender, FormClosingEventArgs e)
{
var button = sender as Button;
if (button != null && string.Equals(button.Name, #"CloseButton"))
{
//FormClosing event raised by a user created button action
}
else
{
//FormClosing event raised by program or the X in top right corner
Globals.Instance.LoggerDictionary["ApplicationLog"].Dispose();
Globals.Instance.LoggerDictionary["OtherLog"].Dispose();
MemoryHandler.Instance.Dispose();
}
}
As seen the FormClosing method ensures that cleanup of unmanaged resources is done. So, in many cases the application moves on to the line below Application.Exit(), and, in the example above, try to write something to the Log, which has already been disposed by the FormClosing() method.
My question is therefore: Does Application.Exit() spawn a new thread where FormClosing() is run from? If not, then why does it continue on?
http://msdn.microsoft.com/en-us/library/system.windows.forms.application.exit(v=vs.110).aspx
Informs all message pumps that they must terminate, and then closes all application windows after the messages have been processed.
This method does not terminate the process. Instant termination is rarely a useful shutdown model because it is unclear what useful shutdown actions would be skipped.
If this method does not terminate the process then clearly your code must continue to run.
This is normal and the right way to shut down the app. If you want to skip certain logic, set a flag bool isShuttingDown and react to it.
No, it does not start a new thread. It also doesn't immediately kill the UI thread. The whole point of Application.Exit is to gracefully exit the application. All forms will be asked to be closed, resources will be cleaned up, all pumped through the main application loop. When the application loop next becomes idle, rather than waiting for more messages, it will instead stop pumping messages and the application will continue running after the call to Appliaction.Run that created the message loop in the first place. That thread can then go on to do whatever (usually end; unless you've added more code).
No it does not spawn a extra thread. Looking at the reference source inside the function it will call each form's FormClosing event, it then returns control to the caller. Once the caller completes and control returns to the message loop that is when the program will actually shut down.
All of this happens on the single UI thread.
I've used Visual Studio 2013 to build a C# application with a single form, and the application has two routines that update the screen. The routines that update the screen need to run on the main thread, so my own threads (which don't interact with the screen) call the BeginInvoke method on the main form when updates are required. However, something is happening somewhere in the application with the result that the two update routines stop executing. I've put logging into the app to track the calls to BeginInvoke and the execution of the update routines, and I can see that when this problem occurs, the BeginInvoke calls are made, but then nothing. When this happens, the whole application seems to freeze. I can't think of what might be causing this. How can I debug this? Is there any way of looking at what's queued to run on the main thread? When I run in debug and break into the application, all threads look normal, and the main thread doesn't appear to be doing anything, so why isn't it processing my pending update tasks?
The Control.BeginInvoke() adds the delegate to an internal thread-safe queue. And posts a message to the UI thread to tell it to go have a look in that queue. The message loop inside Application.Run() gets that message and goes about emptying the queue again, executing the delegates.
So if you don't see this happening then the most obvious reason is that the UI thread isn't inside the Application.Run() loop. A standard mistake you could make is waiting for the thread to complete for example. Very likely to cause deadlock. Never wait, if you need to run code after the thread completes then consider BackgroundWorker's RunWorkerCompleted event or TaskScheduler.FromCurrentSynchronizationContext().
The not-so-obvious failure mode of not seeing anything happening is that you are calling BeginInvoke() far too often. If you do this more than ~1000 times per second, give or take, then you'll flood that internal queue with too many delegates. The UI thread will actually be busy emptying that queue but can never catch up, always finding yet another delegate in the queue after executing one. It goes catatonic when this happens, not taking care of its normal duties anymore. Like responding to input and painting the windows. No fix for this, other than limiting the rate at which you call BeginInvoke(). Do keep the target in mind, you only have to do it as often as the user's eyes can perceive. Updating the UI at a rate more then 25 times per second is just wasted effort.
This might be due to the two update routines attempting to update the UI at the same time. I've seen strange UI behaviour, e.g. partially updated controls, when many UI updates occur in a short space of time when triggered by multiple interleaved events. The two routines are different routines, yes?
A possible way to solve this is to use asynchronous delegate invocation on the UI thread. In the code below I've assumed that your UI is a WinForms Form, and I've named the two routines UpdateA and UpdateB.
private bool isUpdating;
public delegate void UpdateDelegate();
private void UpdateA()
{
if (isUpdating)
{
this.BeginInvoke(new UpdateDelegate(UpdateA));
}
else
{
isUpdating = true;
try
{
// ... do UI updates for A
}
finally
{
isUpdating = false;
}
}
}
private void UpdateB()
{
if (isUpdating)
{
this.BeginInvoke(new UpdateDelegate(UpdateB));
}
else
{
isUpdating = true;
try
{
// ... do UI updates for B
}
finally
{
isUpdating = false;
}
}
}
By the way, I didn't use lock above to synchronise access to flag isUpdating, on the assumption that both UpdateA and UpdateB execute on the UI thread. They are invoked asynchronously by the worker threads via BeginInvoke.
I know this has been asked before, but I don't think these solutions are flexible. The DocumentCompleted event should be used to determine when the load has completed, not as a method for performing work. If you need to perform several different tasks that each have to navigate several times, placing the logic in the DocumentCompleted event turns it into a messy switch/case router that is hard to read and maintain.
You need something that can actually wait during your method performing navigation so you can continue your task in the method you are already in. My first though is an actual Wait() method.
I would think something like this is close:
void WaitForLoad()
{
isLoading = true;
while (isLoading)
{
if (Application.Current == null) break;
Dispatcher.CurrentDispatcher.Invoke(DispatcherPriority.Background, (DispatcherOperationCallback)delegate(object unused) { return null; }, null);
}
}
And set Isloading to false in the DocumentCompleted event.
You should be able to just call this method after whatever action will cause a pageload. It works, it has some issues.
1) it sends the CPU usage for the app up to 35% until the page has loaded, even if nothing else is happening.
2) if the application tries to close while its running, the loop will keep running and leave the app open with no windows, hence the need for the break when the app is null.
Can this be fixed, or am I coming at this all the wrong way?
Edit: I tried implementing the ManualResetEvent solution below, but it led to several other issues that I am not sure can be resolved without creating a messier situation than the one above. Since the WebBrowser is on the UI, locking the thread stop the entire app. If the work is done on the background thread it can be locked, but then accessing the WebBrowser becomes very difficult.
In your situation, it sounds like you want a specific thread to block while waiting for the document to load. In that case, you would do something like this:
protected ManualResetEvent _resetEvent = new ManualResetEvent(false);
public void WaitingThread()
{
_resetEvent.WaitOne();
// Do stuff after the web browser completes.
}
public void LoadWebPage()
{
webBrowser.Navigate(new Uri(url));
webBrowser.DocumentCompleted = (s, e) => { _resetEvent.Set(); };
}
Basically, when the document completes, you signal the event and any threads waiting on the event unblock and continue executing.
I noticed that you use Dispatcher.CurrentDispatcher.Invoke this is good for calling your method that somehow updates UI from another thread. But from code provided, I don't see any code in other thread then UI. So
Run that code on another thread.
On the close event of your application you can make isLoading=false; And more, if the method invoked is kind of long running stuff insert
if(!isLoading)
return;
//or in some other app suitable way break an execution
EDIT:
Even better way to handle this in multithreading, then just simply relay on boolean variable, is using some Synchonization object
I'm showing an animation while my control is loading the data. When the thread finishes, I hide the animation and show the control. So I'm executing this code from a thread:
protected void InvokeEnableBackControl()
{
if (this.InvokeRequired)
{
this.Invoke(new OpHandler(EnableBackControl));
}
else
{
EnableBackControl();
}
}
Sometimes, when I execute this code, the main thread gets hanged in the following code:
protected virtual void EnableBackControl()
{
if (overlayAnimation.TargetControl != null)
{
overlayAnimation.TargetControl.BringToFront();
}
overlayAnimation.SendToBack();
overlayAnimation.Enabled = false;
overlayAnimation.Visible = false;
}
I'm not sure if it's hanged setting the Enable or Visible property. Do you know any circumstance that may hand the application calling these properties from a Control.Invoke?
Note that Control.Invoke is synchronous, so it will wait for EnableBackControl() to return. Consider using Control.BeginInvoke, which you can "fire and forget."
See this answer: What's the difference between Invoke() and BeginInvoke()
I've run into problems before when I'm executing .Invoke on a background thread while my main thread is still busy - this gives the impression that the app is hung, because the .Invoke just sits there, waiting for the main thread to respond that it's paying attention. Possible causes:
Your main thread is blocked waiting for something
Your main form currently had a modal dialog up, so it's not listening to new requests
Your main thread is spinning, either continually checking if something is finished or doing new work. In my case, the main thread spent the first minute spinning up background threads in a tight loop, so it wasn't listening for any .Invoke requests from background threads.
When you attach the debugger, pay special attention to what your main control MessagePump thread is doing - I suspect its lack of attention is the cause of your trouble. If you identify that it's a tight loop in your main thread that's not responding, try inserting a .DoEvents in the loop, which will pause execution and force the main thread to empty the message pump and route any outstanding requests.
Run in debug, make app hang and then pause debug in Visual Studio and inspect threads.
What I discovered is that the actual drawing/painting of controls can be quite slow, esp if you have a lot of them and/or use double buffering for smooth refresh. I was using BeginInvoke to update a listview control from data I was receiving from a socket. At times the updates were happening so fast that it was freezing the app up. I solved this by writing everything I received in the sockets async receive to a queue, and then in a seperate thread dequeuing the data and using BeginUpdate and EndUpdate on the listview and doing all the outstanding updates in between. This cut out a ton of the extra redrawing and made the app a lot more responsive.
You have to use BeginInvoke inested Invoke see this Link