Parallel.For() and Windows message loop - c#

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.

Related

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

Refreshing Windows Forms controls between actions in a 'for' loop

I have a problem that I don't want to work with multithreaded applications since I am testing some code, and I need it single threaded.
It's updating the textbox only after it's all done. I need to somehow keep it updated all the time. Is there another way except with a second thread?
It's updating the textbox only after it's all done. I need to somehow keep it updated all the time. Is there another way expect with a second thread?
There isn't a good way to do this. The problem is, if you're executing code on the UI thread, the UI thread can't process the messages in the message pump, including the ones that way to refresh the TextBox, until your work completes.
In Windows Forms, you can force the application to process these messages by calling Application.DoEvents(), but this is really a bad, bad idea. It's much better (and safer!) to use a BackgroundWorker or some other multithreading technique to push the work into the background thread instead.
You could try the following:
// in for loop
tbxMyTextBox.Text = "New text!";
tbxMyTextBox.Refresh();
I remember having to do something similar in the past.

C# network application threading causes program to block

I am working on a network application with threading. I have an event handler which results in a form showing on the screen. The problem is that the thread that makes this call blocks right after, so the form that shows blocks as well.
I have hacked this problem by making that function change something in the form it's currently in, and then used invoke required to force the new form onto that thread. This is a terrible hack, what is the right way to make the new form.Show() method go through its own thread.
Note that I have tried just making a worker thread that runs only form.show() but the form disappears right after the call.
Thank you,
PM
You don't want UI elements being created in their own threads. The primary thread that launched your application should be the UI thread. Create and show all elements on this thread. All your heavy, long-time or blocking work should be done on their own threads.
You can use BackgroundWorker to execute a single additional task without blocking your UI and get automatic synchronization when you need to make updates to the main (UI) thread such as to update progress bars or show a final result.
If you need multiple threads doing long-running work, use the ThreadPool. You will have to do your own cross-thread synchronization if you need to update UI elements. There are a ton of answers on how to do that already if that's the route you go.
If you have multiple threads that are being blocked while waiting for something to happen, you should use threads yourself. This will keep the ThreadPool from being starved of threads because they are all blocking. (I believe this has been changed in .NET 4 so if you're targeting that version you can probably easily continue using the ThreadPool in this situation.)
Have you tried placing the blocking call in a BackgroundWorker (separate thread)? When that blocking call is done, your background-worker thread completes (which is handled by your main UI thread). Then in that completed handler you can show your form/message or whatever...
If you haven't tried that then give it a shot. Note that i have not tested this since i dont know exactly what you're doing.
Cheers.

How do I Yield to the UI thread to update the UI while doing batch processing in a WinForm app?

I have a WinForms app written in C# with .NET 3.5. It runs a lengthy batch process. I want the app to update status of what the batch process is doing. What is the best way to update the UI?
The BackgroundWorker sounds like the object you want.
The quick and dirty way is using Application.DoEvents() But this can cause problems with the order events are handled. So it's not recommended
The problem is probably not that you have to yield to the ui thread but that you do the processing on the ui thread blocking it from handling messages. You can use the backgroundworker component to do the batch processing on a different thread without blocking the UI thread.
Run the lengthy process on a background thread. The background worker class is an easy way of doing this - it provides simple support for sending progress updates and completion events for which the event handlers are called on the correct thread for you. This keeps the code clean and concise.
To display the updates, progress bars or status bar text are two of the most common approaches.
The key thing to remember is if you are doing things on a background thread, you must switch to the UI thread in order to update windows controls etc.
To beef out what people are saying about DoEvents, here's a description of what can happen.
Say you have some form with data on it and your long running event is saving it to the database or generating a report based on it. You start saving or generating the report, and then periodically you call DoEvents so that the screen keeps painting.
Unfortunately the screen isn't just painting, it will also react to user actions. This is because DoEvents stops what you're doing now to process all the windows messages waiting to be processed by your Winforms app. These messages include requests to redraw, as well as any user typing, clicking, etc.
So for example, while you're saving the data, the user can do things like making the app show a modal dialog box that's completely unrelated to the long running task (eg Help->About). Now you're reacting to new user actions inside the already running long running task. DoEvents will return when all the events that were waiting when you called it are finished, and then your long running task will continue.
What if the user doesn't close the modal dialog? Your long running task waits forever until this dialog is closed. If you're committing to a database and holding a transaction, now you're holding a transaction open while the user is having a coffee. Either your transaction times out and you lose your persistence work, or the transaction doesn't time out and you potentially deadlock other users of the DB.
What's happening here is that Application.DoEvents makes your code reentrant. See the wikipedia definition here. Note some points from the top of the article, that for code to be reentrant, it:
Must hold no static (or global) non-constant data.
Must work only on the data provided to it by the caller.
Must not rely on locks to singleton resources.
Must not call non-reentrant computer programs or routines.
It's very unlikely that long running code in a WinForms app is working only on data passed to the method by the caller, doesn't hold static data, holds no locks, and calls only other reentrant methods.
As many people here are saying, DoEvents can lead to some very weird scenarios in code. The bugs it can lead to can be very hard to diagnose, and your user is not likely to tell you "Oh, this might have happened because I clicked this unrelated button while I was waiting for it to save".
Use Backgroundworker, and if you are also trying to update the GUI thread by handling the ProgressChanged event(like, for a ProgressBar), be sure to also set WorkerReportsProgress=true, or the thread that is reporting progress will die the first time it tries to call ReportProgress...
an exception is thrown, but you might not see it unless you have 'when thrown' enabled, and the output will just show that the thread exited.
Use the backgroundworker component to run your batch processing in a seperate thread, this will then not impact on the UI thread.
I want to restate what my previous commenters noted: please avoid DoEvents() whenever possible, as this is almost always a form of "hack" and causes maintenance nightmares.
If you go the BackgroundWorker road (which I suggest), you'll have to deal with cross-threading calls to the UI if you want to call any methods or properties of Controls, as these are thread-affine and must be called only from the thread they were created on. Use Control.Invoke() and/or Control.BeginInvoke() as appropriate.
If you are running in a background/worker thread, you can call Control.Invoke on one of your UI controls to run a delegate in the UI thread.
Control.Invoke is synchronous (Waits until the delegate returns). If you don't want to wait you use .BeginInvoke() to only queue the command.
The returnvalue of .BeginInvoke() allows you to check if the method completed or to wait until it completed.
Application.DoEvents() or possibly run the batch on a separate thread?
DoEvents() was what I was looking for but I've also voted up the backgroundworker answers because that looks like a good solution that I will investigate some more.

Categories

Resources