Multithreading a GUI using backgroundworkers - c#

There is 2 Backgroundworkers in my project:
BGW1: the first worker is used to read data from a controller and convert the data into the right format
BGW2: the second worker is used to pass the converted data and objects to the GUI using the ReportProgress functionality
The entire process needs to be as real time as possible and the messages are coming approx every 0.5 ms. The MainThread becomes flustered pretty quick when it has to update 800 points every 5-10 ms.
This causes the GUI to become unresponsive if i update at a faster rate than 10fps.
A solution i have found online, is this:
Alternate Way of Multithreaded GUI
I have tryed to adopt this methodology to my background workers by setting
// Prevent the framework from checking what thread the GUI is updated from.
theMainForm.CheckForIllegalCrossThreadCalls = false;
in the main form. This allows me to update the gui from a seperate thread not the main thread, from what i understand.
Using this line in the main should mean that i can access the GUI elements from other threads that arent the main thread, and i dont need to use ReportProgress
to update the Chart, so i tried updating the Chart from my DoWork portion of BGW2.
The update works from DoWork, but it seems to still just refer the Data to the MainThread and that thread then updates the chart, which results in an unusable GUI again.
Do i have to get rid of the backgroundworkers completly and only use Threads for the solution from the link to work? Or is there some sort of trick to getting this method to work with backgroundworkers.

Well, don't update that often. Just stick to a fixed refresh rate, and use a ConcurrentQueue to pass the data points between the BackgroundWorker that reads the data, and the GUI that renders it. A simple Timer should work well enough - every five seconds, read everything out of the ConcurrentQueue and update the chart.
Don't update the UI from multiple threads. There's a reason why the checks are there.

One background worker really is enough.
The expensive parts of this operation are;
Synchronizing back to the UI thread
Blocking the worker while you do it.
The solve the performance issue, minimise #1. Don't post every item, post many items every x milliseconds.
In fact, I'd recommend not using a background worker at all - the ReportProgress event blocks your worker thread.

Have you tried to enforce the events being handled? This will empty the events queue so the form becomes responsible for the user. Nevertheless you better go with updating the GUI at a fixed rate, as pointed out by Luaan.

Related

Parallel.For() and Windows message loop

Recently I was able to convert a for loop into a Parallel.For loop to speed up an heavy task in my WinForms application initialization.
I was quite surprised though, to see some OnPaint() calls coming through when the Parallel.For() is in action.
Why does this happen? Is there any way to prevent the UI from working during a Parallel.For?
EDIT: I want to save time but not change the program logic: I want the Parallel.For to work exactly as the for and save time. UI depends on the result of the for loop and the OnPaint() fails because the data is not ready yet.
You should never block UI thread (prevent the UI from working). It makes the application unresponsive which users don't like. You should handle it gracefully by graying out form and showing progress bar.
Try calling this.SuspendLayout() on the form that represents the UI. After computations are finished allow again updating of the UI with this.ResumeLayout()
Edit:
Also you should not run code which updates controls from a thread different from the one which has created them. If doing so, it has to be done through the Invoke methods.

Is it possible to put a form control on its own thread?

I'm using a DataGridView and some operations that I do cause it to become unresponsive for periods of time. Normally I would put data processing in its own thread to make the form more responsive, but in this case it's the DataGridView itself that's taking so long.
This leads me to wonder whether it's possible to have the main form on one thread and the DataGridView on another thread so it doesn't prevent the main form from responding.
I completely understand that doing so is probably not 'safe' and likely opens up a can of worms that makes it hardly worth trying and I fully expect this post will be getting down votes for merely suggesting such a ridiculous idea.
Is this possible? And if so how would you go about it?
EDIT: I figured out how to fix the problem at hand. The short answer was to use a flag when setting the RowCount so CellValueNeeded() can bail out immediately. There's really more to the story and I had already been doing this partially, but that's the gist of it.
Short answer is no, because the control needs to interact with other controls (or at least the window), and they all need to be on the same thread.
Doing so seems to imply that you're doing processing on the UI thread, which itself is also a big no-no. You should run all of your major processes on their own thread, and then save the final presentation for the UI thread -- work on one thread, screen updates on another.
It is definitely possible to have multiple UI threads in a given application. However it is not possible to compose UI components from different threads onto the same Form. For a given form all of the components must be on the same thread
The best way to fix this problem is to move the data processing itself onto a separate thread. Only do the absolute minimum to update the UI from the UI thread. That should help with the responsiveness
take a look into use of virtualization in the grid.
And please give code sample to what operation is taking too long!
No, but from events fired from the dataGridView you could send a worker to perform async tasks and then update the dataGridView using the controls Invoke method from the worker thread

Redrawing windows application

I have a software in C# I'm writing and every time its doing a hard task and I switch windows to let it complete the window screws up. Not sure how to word it but all of the buttons disappear or become "holes" . I know the application is running because the progress bar shows up again after a while. How do I fix this? I've been searching and I'm sure it has something to do with doubleBuffering.
you normally solve this by executing your resource intensive process in a separated thread than the main UI thread, in this way the UI thread can refresh the UI as needed and your long lasting operation is completed in parallel. After the background / worker thread has completed its task the control flow will return to the application.
Things are a bit more complicated when you want to update the status bar in the UI thread from the worked thread, usually you have to use the Invoke methods because you definitely should not even try to access and modify UI controls from another thread.
a bit cheaper method which kind of works but can have some issues from time to time is to include in your long lasting operation a call to Application.DoEvents() from time to time, for example if you are in a loop, every few iterations of the loop (depends on how much time it takes to execute a single iteration and on how many iterations you have in total); this method works and saves you completely from start working with multiple threads but is also considered less reliable.
As LarsTech already pointed out, use the BackgroundWorker-Class, especially for tasks which take longer than just a few seconds.
Make sure to use ReportProgress in your Backgroundworker to notify your Progressbar.
Good links worth studying:
http://www.albahari.com/threading/part3.aspx
http://www.codeproject.com/Articles/99143/BackgroundWorker-Class-Sample-for-Beginners

Are there alternatives to invoke in WPF when passing data from a different thread?

I know how to pass data from a worker thread to the main thread via Invoke/BeginInvoke.
I can also pull from a thread safe collection with a timer from the main thread.
I prefer using tasks (Task.Factory.StartNewTask()) and using Backgroundworker with them seams a bit clumsy.
Sometimes the gui is a bit laggy which is due to (Begin)Invoke I assume.
Pulling with a timer also doesn't feel like the right way.
Creating a new Backgroundworker for each new task seams also strange.
Are there any other possibilities?
In .NET, memory is shared within an AppDomain, which means all threads can access all data. So, what you're actually doing is controlling access to particular bits of data from particular threads so they don't interfere with each other.
Invoke and BeginInvoke allow you to run code on the UI thread, which is useful because UI controls can only be accessed from the UI thread. BackgroundWorker is another solution, as is SynchronizationContext.
However, they all work by sending known windows messages to the UI message loop. If you call Invoke too often, you send too many messages and the UI thread is swamped which makes the UI "a bit laggy".
If this happens, you must slow down the rate that messages are sent. There are a couple of ways to do this:
1) Call Invoke less frequently: this means waiting for bigger "chunks" of state changes in your background thread before it calls Invoke to update the UI.
2) Use a UI Timer: there is no point in trying to update the UI faster than the human eye can detect. A UI Timer also sends windows messages to the UI message loop, but at a known rate. The Tick handler can then pull the necessary data from shared memory to update the UI.
Both approaches have their strengths and weaknesses. The choice really depends on how easy it is to group state changes in the background thread into bigger chunks, while making sure the UI doesn't miss any state changes.

C#: "not responding" window when program is doing some background processing

In my C# project I have a form that is displayed which shows a progress bar.
Some processing is then done which involves communication over the internet.
While this processing is occurring the form says "Not Responding" when run in Win 7, in XP the form just goes white.
Either way, it is not acceptable.
Do I need to use threads to solve this problem?
What are some of the basics of threads that I would need to use in this scenario?
Your processing must be done within a thread.
Out of your thread you have to invoke your progress bar to show the progress.
progressBar1.Invoke((MethodInvoker)delegate
{
progressBar1.Value = (int)((i / limit) * 100);
});
Yes you have to use threads to keep your UI responsive while something gets done in background. But this question cannot be just answered just like "use Threads to solve it", because there are a lot of forms in which you could use threads. (Backgroundworker, Threadpool, Asynch IO, Creating a Thread, Task Parallel Library, CCR, and a lot more you could imagine for every kind of parallelization scenarios).
As you said you are doing some processing which needs connecting to internet. Where does the most amount of time spent? is it IO over network which takes most time in that case probably Asynchronous IO makes a lot of sense. If time spent is in one huge processing operation then Background worker is perfect, but if this processing can be further broken down into smaller chunks of parallel processing tasks then TPL or ThreadPool is preferred. Till now I am talking only about some processing which happens on Windows forms event, and keep the UI responsive. But based on the scenario there are numerous other options you could use to make threading work for you.
Asynch IO doesnt look like you are doing threading but it more matches with eventing model of winforms. So you could look at that if you are very comfortable with event based programming.
Threadpool looks more like a queue of workers to which you could keep throwing all the work needs to be done, and the framework figures out how many threads to run based on the kind of machine you are using (dual core, quad core etc) and it would get your work items doen in optimal way.
Bottom line its not one answer to use one over other, instead based on the kind of problem you are solving threading model needs to be decided on.
A cheaper option is to add the line Application.DoEvents() inside whatever loops your app is running, which will cause it to process messages each time it gets there.
If you use System.Net.WebClient, you can use DownloadDataAsync() to communicate in a non blocking way.
The System.Net.Sockets.Socket class proviede non blocking communication, too.
Sockets example
WebClient example
Yes, better way is use BackGroundWorker component. It is wrapper over threads, so you don't need to manage threads. You can get more info from Background worker on MSDN
As long as the program remain in the function to process something, the UI will not update. That is why you may need to start a background thread, so that your UI can continue functioning while your background thread can do the work. An alternatively is to use asynchronous functions.
example of background thread
From your description I'll assume that all your work is currently being done on a single thread, the main thread which is also used for your GUI.
The progress bar can only update when that main thread gets a chance to check its state and apply any expected changes.
Therefore it is important that your processing work does not occupy the main thread for extended periods of time.
There are two main approaches to handling this:
Stepping the processing activity.
Break down the processing step into a number of serial tasks - each short in nature.
Progressively call each of these serial tasks in the OnIdle event on your main thread.
Using a background thread.
See other answers giving more detail on how this would work.
The stepping approach can be useful if you want to avoid the sublties of thread synchronisation. The threading approach is probably better but only essential if it is impossible to guarantee serial short steps.

Categories

Resources