I have been writing ASP.NET web application for years now, but haven't really worked on large windows forms projects. I now need to work on one, so I am looking on some pointers on how a large windows forms project should ideally be structured. More specifically, I would like to know how to handle multiple threads. Assume you have a process which takes some time to complete - you do not want to have the ui window frozen and not responding. So that logic needs to move in a separate thread. If this thread accesses the UI, then it will cause exceptions. Invoke seems to do the trick, but looks very ugly and cumbersome to write and read!
So, in reality, what are the best practices? What type of threads should one launch, and how should these threads be split between UI and logic? Any sample code to get started?
here is a short way to use the backgroundworker
public Form1()
{
InitializeComponent();
BackgroundWorker worker = new BackgroundWorker();
worker.WorkerReportsProgress = true; //set to true to fire the progress-changed event
worker.DoWork += doWork;
worker.ProgressChanged += progressChanged;
}
void progressChanged(object sender, ProgressChangedEventArgs e)
{
int progress = e.ProgressPercentage; //Progress-Value
object userState = e.UserState; //can be used to pass values to the progress-changed-event
}
void doWork(object sender, DoWorkEventArgs e)
{
object argument = e.Argument; //Parameters for the call
bool cancel = e.Cancel; //Boolean-Value for cancel work
object result = e.Result; //Object for a return-value
}
As soon as you use a different thread you will have to switch back to the UI thread when touching the UI.
someForm.BeginInvoke() can do this but there are more options.
The BackgroundWorker can do the switching for you.
In .NET 4.5/ C# 5 you can use async/await; the continuation will be called on the original thread.
In general, try to untangle the logic as much as you can from the UI so you do not need to switch thread too often.
There are lots of ways to achieve UI responsiveness, execute long running tasks, achieve parallelism. You have to select the right way for your application -
This article by Jon Skeet is always a bonus to start with.
You can call Synchronous methods Asynchronously using any of these styles as per your application design and requirements
More difficult situations, such as coordinating the work of multiple threads, or handling threads that block
There are a number of ways to expose asynchronous features to client code. Read here for the Event-based Asynchronous Pattern - which prescribes the recommended way for classes to present asynchronous behavior.
Background Worker comes in handy when you have a single long running task.
Hope this gives you a head start.
Related
I'm having the worst time wrapping my head around threads/background processes. My issues seem common enough to a certain point but I've yet to find a good example that meets my needs.
The classic example goes like this:
My UI freezes when a certain long running task/process runs -I want to be able to at least move/minimize the UI.
Classic replies include Threading and Task Factories and BackgroundWorker solutions.
but no matter how I implement them I get poor results.
In my program, I'm executing another application and waiting for it to finish. For the sake of simplicity let's say I'm doing it like so:
Process p = Process.Start("notepad.exe somefile.txt");
p.WaitForExit();
//read somefile.txt
Clearly my application UI would hang while WaitForExit() grinds away waiting for me to close notepad.
I've attempted a number of suggested means around this but I get painted into one of two corners:
My interface still hangs, then reads somefile.txt just fine when I close notepad.
The Process (Notepad) runs fine but my application reads somefile.txt immediately before I have closed notepad (So I guess it's running asynchronously)
Most examples I see involve counting to a high number -simple but not quite what I'm doing. Firing off this "external" process complicates things a bit.
Thanks for your time and consideration!!
BackgroundWorker seems appropriate here; it should be configured something along those lines:
var worker = new BackgroundWorker();
worker.WorkerReportsProgress = false;
worker.WorkerSupportsCancellation = false;
worker.DoWork += worker_DoWork;
worker.RunWorkerCompleted += worker_RunWorkerCompleted;
worker.RunWorkerAsync();
Then you have the handlers:
void worker_DoWork(object sender, DoWorkEventArgs e)
{
//start notepad process here.
}
void worker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
//read somefile.txt here.
}
From the sounds of things your application isn't running the Process.WaitForExit call on a separate thread otherwise there wouldn't be any hanging.
BackgroundWorker, Thread and the ThreadPool are all useful tools, but they can be difficult and cumbersome to work with and get right, the Task Parallel Library with System.Threading.Task has somewhat "superseded" using threads directly for most operations you need to perform asynchronously.
See: Threads and the new Task library in C#
So your code becomes.
Task.Factory.StartNew(() =>
{
var proc = new Process("...");
proc.WaitForExit();
File.Read("...");
});
I have some code that I wrote, which does what I want. However, I am not quite sure how, exactly, it works. The part I am having the most trouble with is the last part. I had a textBox1.Text = "test" which did not work. I got a run time error about it being called from a different thread. When I put the textBox1.Invoke(etc etc), it worked as expected. Why?
As you can see, I know just enough to be dangerous and I really want to understand what's going on here instead of blindly copying and pasting from sites around the web.
I have the following in a class named SerialCommunicator:
public SerialCommunicator(SerialPort sp)
{
this.sp = sp;
sp.ReceivedBytesThreshold = packetSize;
sp.DataReceived += new SerialDataReceivedEventHandler(sp_DataReceived);
sp.Open();
}
public void sp_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
Thread.Sleep(50);
SerialPort s = (SerialPort)sender;
byte[] buffer = new byte[128];
s.Read(buffer, 0, s.BytesToRead);
}
Then, in my Form1.cs I have a button that when pressed does the following:
private void btnPortOK_Click(object sender, EventArgs e)
{
string comPort = cboComPorts.SelectedItem.ToString();
SerialPort sp = new SerialPort(comPort, 9600, Parity.None, 8, StopBits.One);
sp.DataReceived += new SerialDataReceivedEventHandler(DataHasBeenReceived);
comm = new SerialCommunicator(sp);
}
public void DataHasBeenReceived(object sender, EventArgs args)
{
textBox1.Invoke(new EventHandler(delegate { textBox1.Text += "test"; }));
}
This is thread-affinity. UI controls don't like to be touched by anything except the thread that created them, but the DataReceived thread happens from a different thread. Adding a call toControl.Invoke pushes an item of work back to the UI thread, so the Text updated can succeed.
I am not an expert on this (there will likely be better answers than this). But as I understand it, the GUI thread "owns" your form. So when you try to update it from a different thread you are crossing the streams.
The Invoke is a way to ask the GUI thread to run a method. Method that it runs is your textBox1.Text += "test";
The idea is by invoking a delegate, that will ask the GUI thread to make the change, rather than just changing the value yourself. This allows allow the change to be done in a thread safe manner.
Here is a good article by Jon Skeet on this issue:
http://www.yoda.arachsys.com/csharp/threads/winforms.shtml
Events are called from the thread where they happen. (Unless specified otherwise).
Think about this way:
When you activate the event, it is actually called as a finction EventName(). So calling an event means actually going to all the methods that were registered to that event and doing them.
But, this is done in the same thread in a serial way.
So if an event happened in a thread that is not your UI thread you'll get theat error.
The issue is that the GUI components only accepts modifications from the GUI thread. So when other threads want to modify the GUI, then they must queue their modification code using measures like control.Invoke(...) which will queue the delegate to be processed as soon as possible on the GUI event queue, and thus the correct thread.
What you run in to is that one of the built-in checks are fired than controls that the calling thread indeed is the correct thread. It is a security measure that makes debugging easier (if they were not present you would have to debug subtle threading issues instead...)
textBox1.Text = "test" doesn't work because you are calling it from another thread (i.e. the DataHasBeenReceived event) then the thread who owns the textbox. That's usually the thread in which your application runs and that creates your GUI interface (and thus your textbox). Invoke works because that methods switches to the GUI thread, sets your text and then switches back to the thread of your DataHasBeenReceived event.
In Net 1.0 and 1.1 you could use GUI controls from another thread then then the one that owned them but this resulted in a lot of problems when threads started accessing the controls at the same time. So, since net 2.0 Microsoft changed that.
If you want to know if must use invoke or not (i.e. if a method can be called from the both the GUI thread or another thread), you can use the property InvokeRequired combined with an if else. A invoke call is slightly more expensive then a direct manipulation of the control.
Client/server desktop application using C#, WCF, WPF. Since pretty much every action is going to require a trip to the server (list/create/save/delete/etc), every action has the potential to freeze the entire UI. Here's an example of a naive implementation with a call to service.GetAll() which could take a "long" time (more than a few hundred milliseconds):
private void btnRefresh_Click(object sender, RoutedEventArgs e)
{
vm.Users.Clear();
foreach (var user in service.GetAllUsers())
vm.Users.Add(user);
}
(Aside: I'd love to know why List has AddRange and ObservableCollection doesn't.)
BackgroundWorker to the rescue:
private void btnRefresh_Click(object sender, RoutedEventArgs e)
{
var worker = new BackgroundWorker();
worker.DoWork += (s, e) =>
{
Dispatcher.BeginInvoke((Action)delegate() { btnRefresh.IsEnabled = false; });
e.Result = service.GetAllUsers();
};
worker.RunWorkerCompleted += (s, e) =>
{
vm.Users.Clear();
foreach (var user in (List<UserDto>)e.Result)
vm.Users.Add(user);
Dispatcher.BeginInvoke((Action)delegate() { btnRefresh.IsEnabled = true; });
};
worker.RunWorkerAsync();
}
(Aside: code above has been simplified, but that's the gist of it.)
The code using BackgroundWorker works exactly how I want it to. The app remains responsive at all times, and the button is disabled for the duration of the call. However, this means adding 15 lines to every possible action the user might make.
Say it ain't so.
No, BackgroundWorker is not the only way, but it's one way. Any other way will allso include some form of asynchronous construct with the need to use Dispatch.BeginInvoke to update the UI. You could for instance use the ThreadPool:
ThreadPool.QueueUserWorkItem(state => {
Dispatcher.BeginInvoke((Action)delegate() { btnRefresh.IsEnabled = false; });
foreach (var user in service.GetAllUsers())
vm.Users.Add(user);
Dispatcher.BeginInvoke((Action)delegate() { btnRefresh.IsEnabled = true; });
});
If this is a recurring pattern (a button will trigger some action that should be performed asynchronously, with the button being disabled during the process) you can wrap this into a method:
private void PerformAsync(Action action, Control triggeringControl)
{
ThreadPool.QueueUserWorkItem(state => {
Dispatcher.BeginInvoke((Action)delegate() { triggeringControl.IsEnabled = false; });
action();
Dispatcher.BeginInvoke((Action)delegate() { triggeringControl.IsEnabled = true; });
});
}
...and call it:
PerformAsync(() =>
{
foreach (var user in service.GetAllUsers())
vm.Users.Add(user);
}, btnRefresh);
As an option to using the ThreadPool, you should also perhaps look into the Task Parallel Library.
When doing this you should pay attention to how you handle UI state. For instance of you have more than one control which triggers the same action, make sure that all of them are disabled during the action.
Note: these are just quick ideas. The code has not been tested so it may contain errors. It's more to be regarded as discussion material than finished solutions.
WCF provides the ability to make all service calls asynchronously. When you create the service reference in your project, the add service reference dialog box has an "Advanced..." button. Clicking that you will see the option for "Generate Asynchronous operations". If you click that check-box then every operation will be generated in both a synchronous and asynchronous manner.
For example, if i have an operation "DoSomething()" then after checking this box i will get code generated for calling DoSomething() and DoSomethingAsync().
You will also get a Service.DoSomethingCompleted event that you can use to define a callback handler when the service call returns.
This is the method we used to make service calls without locking the UI.
Here is a rather complicated example provided by Microsoft on how to do this: http://msdn.microsoft.com/en-us/library/ms730059.aspx
It is not the only way. I recommend Task (or one of the higher-level abstractions for Task, such as Parallel or PLINQ).
I have a review of various approaches to asynchronous background operations on my blog.
The current state of things does require some boilerplate code, regardless of which approach you choose. The async CTP shows where things are going - towards a much, much cleaner syntax for asynchronous operations. (Note that - at the time of writing - the async CTP is incompatible with VS SP1).
Well, BackgroundWorker is not the only option you have but in order to accomplish what you want you still need to use multiple threads or asynchronous operations in order to not block while you wait for the long-running operations to finish.
And, because WPF requires that all code accessing the UI run on the same thread you do have to do some context switching when you call or access data or code on the UI thread. The way to ensure a call will run on the UI thread in WPF is to use the Dispatcher class.
Another simple way of keeping the UI responsive is to queue work item on a thread in the Thread Pool which is done using the ThreadPool class.
// assuming the the following code resides in a WPF control
// hence "this" is a reference to a WPF control which has a Dispatcher
System.Threading.ThreadPool.QueueUserWorkItem((WaitCallback)delegate{
// put long-running code here
// get the result
// now use the Dispatcher to invoke code back on the UI thread
this.Dispatcher.Invoke(DispatcherPriority.Normal,
(Action)delegate(){
// this code would be scheduled to run on the UI
});
});
As always, there's more than one way to skin the cat but be aware that each technique has advantages and disadvantages. For instance the method outlines above could be useful because it doesn't have that much code overhead but it may not be the most efficient way in may cases.
Other options are available including using the BeginXXX - EndXXX methods of the classes you're using if they provide any (such as the SqlCommand class has BeginExecuteReader EndExecuteReader). Or, using the XXXAsync methods if the classes have that. For instance the System.Net.Sokets.Socket class has ReceiveAsync and SendAsync.
No this is not the only option. This question is more about how are you designing your application.
You can take a look at Windows Composite Applicaiton Framework (Prism), which provides features like EventAggregator which can help you publish application wide events out and subscribe it at multiple locations within your app and take actions based on that.
Also as far as being worried about having too many lines of code, you may want to layer your application architecture in such a way that you can refactor and reuse as much code as possible. This way you have these background workers handling all your service responses in one layer while you can leave your UI layer detached from it.
No it's not the only way, but it is one of the simpler ones (at least compared to setting up your own thread, or pushing a task to a thread pool thread and arranging an event on completion).
You might be able to simplify a little bit by writing a static method somewhere that takes two parameters, the callback functions, and handles the rest for you, that way you won't have to write all the same boiler plate every time you need to make an async call.
No, certaily not.
You can create a raw Thread and execute time taking code in it and then dispatch the code to the UI Thread to access/update any UI controls.More info on Disptacher here.
Refer to this for a great information about Threads in c#.
I'm trying to load loadingForm like below code. But it doesn't work, the loadingForm doesn't disappear, the event RunWorkerCompleted doesn't get called.
And also, I need to call loadingForm and backgroundWorker multiple times, so how do I completely dispose the loadingForm and the backgroundWorker after each call?
I think that there're many things wrong in my code but I don't know how to fix it. Could you show me how to solve my problem and point out where I need to fix? Thanks a lot in advance.
public partial class loginForm : Form
{
//....
private loadingForm lf;
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
lf.Show();
While (backgroundWorker1.isBusy)
Application.DoEvents();
}
private void backgroundWorker1_RunWorkerCompleted(object sender, DoWorkEventArgs e)
{
lf.Close();
}
private void connect()
{
//....
Thread mainThread = new Thread(ThreadStart(listentoServer));
mainThread.Start();
}
private void listentoServer()
{
//....
lf = new loadingForm();
backgroundWorker1.RunWorkerAsync();
//....
backgroundWorker1.CancelAsync();
//....
}
}
There's a lot of things wrong with your code. If you can, try to take a step back and describe what exactly you want to do.
BackgroundWorker uses the Event-based Asynchronous Pattern (EAP). As such, it requires a thread context in which to live. UI threads satisfy this requirement, but manually-created Thread instances do not (unless you install one or make the instance a secondary UI thread).
Similarly, UI components bind to a particular thread. They require an STA thread that does message pumping (e.g., Application.DoEvents).
It looks to me like you're creating a manual Thread and then creating UI components from that thread (so you know that the thread should be STA and include a message pumping loop, neither of which are in your code). Then that thread starts a BGW which does message pumping.
It's not clear what you're trying to accomplish here - maybe displaying a dialog in a separate thread?
Multiple UI threads in a WinForms app is not an officially supported scenario AFAIK, though some people have gotten it working. I've never seen a need for it, though.
According to what you have shown (which is admittedly incomplete, so this may not be the problem), you are not hooking up your event to the backgroundWorker_DoWork and backgroundWorker_RunWorkerCompleted event handlers. Somewhere (after you instantiate your backgroundWorker), you should have this:
backgroundWorker.DoWork += new EventHandler(backgroundWorker_DoWork);
backgroundWorker.RunWorkerCompleted += new EventHandler(backgroundWorker_RunWorkerCompleted);
As a disclaimer, this was written by hand, so the event names or EventHandler types may be incorrect.
i really don't know how to fix your code definitively, or if your code even works the way you have it, i can only give you the following guidance.
use CancellationPending property of background worker, not the IsBusy property
when working with windows forms and threaded code, always use the Invoke/BeginInvoke methods to make sure you marshal your call back to the thread that the control originated from.
There is a sequence for FORM(some UI) should get downloaded using service.
Currently, this download is in a BackgroundWorker Thread.
Now, since the performance is slow... We decided to categories the FORMS into 2 and start downloading parallely using another BackgroundWorker on top of the existing Thread.
Now, the scenario is the either of this BackgroundWorker should wait for other to complete.
So, how to implement it.
I tried with AutoResetEvent. but, i could not achieve this.
Any help is appreciated.
I don't think that the scenario is really that one BackgroundWorker should wait for another. What you really want is to fire some UI event after (and only after) both of them complete. It's a subtle but important difference; the second version is a lot easier to code.
public class Form1 : Form
{
private object download1Result;
private object download2Result;
private void BeginDownload()
{
// Next two lines are only necessary if this is called multiple times
download1Result = null;
download2Result = null;
bwDownload1.RunWorkerAsync();
bwDownload2.RunWorkerAsync();
}
private void bwDownload1_RunWorkerCompleted(object sender,
RunWorkerCompletedEventArgs e)
{
download1Result = e.Result;
if (download2Result != null)
DisplayResults();
}
private void bwDownload2_RunWorkerCompleted(object sender,
RunWorkerCompletedEventArgs e)
{
download2Result = e.Result;
if (download1Result != null)
DisplayResults();
}
private void DisplayResults()
{
// Do something with download1Result and download2Result
}
}
Note that those object references should be strongly-typed, I just used object because I don't know what you're downloading.
This is really all you need; the RunWorkerCompleted event runs in the foreground thread so you actually don't need to worry about synchronization or race conditions in there. No need for lock statements, AutoResetEvent, etc. Just use two member variables to hold the results, or two boolean flags if the result of either can actually be null.
You should be able to use two AutoResetEvent's and the WaitAll function to wait for both to complete. Call the Set function on the AutoResetEvent objects in the respective OnRunWorkerCompleted event.
Jeffrey Richter is THE guru when it comes to multi threading and he's written an amazing library called Power Threading Library which makes doing tasks like downloading n files asynchronously and continuing after they are all completed (or one or some), really simple.
Take a little time out to watch the video, learn about it and you won't regret it. Using the power threading library (which is free and has a Silverlight and Compact Framework version also) also makes your code easier to read, which is a big advantage when doing any async stuff.
Good luck,
Mark
int completedCount = 0;
void threadProc1() { //your thread1 proc
//do something
....
completedCount++;
while (completedCount < 2) Thread.Sleep(10);
//now both threads are done
}
void threadProc2() { //your thread1 proc
//do something
....
completedCount++;
while (completedCount < 2) Thread.Sleep(10);
//now both threads are done
}
Just use 2 BackgroundWorker objects, and have each one alert the UI when it completes. That way you can display a spinner, progress bar, whatever on the UI and update it as download results come back from the threads. You will also avoid any risks of thread deadlocking, etc.
By the way, just so we are all clear, you should NEVER call a blocking function such as WaitAll from the UI thread. It will cause the UI to completely lock up which will make you users wonder WTF is going on :)