I have a lot of long-running activities and think that spawning this activity off to another thread will be a good way to have my U.I be able to update to show its current status.
However, when I use the following:
Thread t = new Thread(() =>
{
/* do magic here */
});
Nothing inside the foreach loop that's inside the thread gets done. But, when I don't use a thread, the work does get done, so I know it's not a problem with the loop.
Any suggestions?
You may also want to take a look at BackgroundWorker as it nicely encapsulates everything.
Are you even starting the thread?
newThread.Start();
In the sample you provide you merely declare it.
Also bear in mind that if you're using WinForms, you won't be able to update the UI directly from any thread other than the one that created it; for example, modifying a progress bar or label control from within your foreach loop.
You need to start the tread, t.Start();
Creating the instance just creates an managed wrapper for a thread. Calling Start will set things in motion and eventually make your code run on a separate thread.
Probably you haven't started the thread, so its not running yet.
However, in your case its usually better to use BackgroundWorker class, this will create the thread for you and provide thread-safe way to update the UI with the progress of the threads work.
Related
I have a simple app that read a database and then aftersome manipulation write the results on another one.
The first lines of code update the ui with a message for the user and an onscreen log, then is all wrapped inside a try/catch construct with usings and other try/catch annidated.
message.AppendText("** Message for the user that appear only after the try block's execution **\n");
message.ScrollToEnd();
try
{
using(SqlConnection...)
{
business code
}
}
catch
{
bbbb...
}
In the end it works, but the ui is only updated when it finishes all.
I can understand why what's inside the try must wait the end, but why the first lines don't affect the ui till the end of the successive block?
And how can I create more responsive ui?
I first tried creating a thread for any connection (one has a timout of 5 seconds), and one for the businness code.
Ok, it was overkill, but was experimenting.
I had so much problems sharing the connections between threads and interacting with the main window's ui that abandoned the idea and rewrited all as described above.
People here have suggested creating a responsive UI. This is one way to do that. At the top of your code file, add:
using System.Threading;
Move all the stuff that takes a long time to a new method:
public void LoadStuff()
{
// Do some stuff that takes a while here
}
Replace the original stuff with this code:
Thread callThread = new Thread(new ThreadStart(LoadStuff));
callThread.Start();
Now, anytime you need to update your UI from LoadStuff you have to encapsulate it (surround it) with this code. The reason for this is only the thread that creates the UI can modify it. So, we have to tell our new thread to refer back to the old thread to execute the code. Therefore, inside LoadStuff, after you compute a bunch of data, to update your UI use this:
this.Dispatcher.Invoke(new Action(() =>
{
// Code to update UI here
}));
Like others have suggested, there are others ways to increase UI speed, and I was not the first to suggest using a different thread to compute. But I just wanted to show you a way to do it.
In addition to moving long-running processes off of the UI thread, there are some UI tricks that you can do to help make user interaction feel a little better. For example, if an action takes more than about 0.1 seconds, try fading in a message (e.g. "Loading...") to let the user know that there is something happening. Once you get the data back, fade this message back out.
You may also want to try animating the UI update to avoid the "stuttering" sensation.
I know that simplest way to update a label from another thread is:
void DoSomething()
{
if (InvokeRequired)
{
Invoke(new MethodInvoker(DoSomething));
} else
{
// Do Something
}
}
My question is if instead of the if that require to update the GUI from another thread is it possible to change back to the main thread and update the GUI from there ?
Actually, the simplest way to do this is
Invoke(new MethodInvoker(DoSomething));
if you call it from another thread for sure, ie. if you know, that InvokeRequired will always be true.
Also, you could use a WinForms Timer to poll for changes of, say, a text field. This timer runs in the GUI thread. That is a pretty good solution if you have hundreds of events per second. Or at least "a lot of". This way you don't have too many switches to the GUI thread (which always take considerable amount of time).
Of course its possible ... you can use class called Dispatcher (System.Windows.Threading). The main purpose of this class is to dispatch "requests/calls" on thread ... and for gui thread there is instance of such dispatcher available for all controls. You can find this instance as member of your Window for example ...
The catch is that you using dispatcher alraedy (in code you posted) in some way ... if you call Invoke inside Form this default/gui dispatcher is used. And "IF" is there for reducing count of invocation from gui thread itself.
It works like "am i in ui thread? No? Then give dispatcher request of calling this same method on UI thread! ... Am i in UI Thred? Yes! Ok, i am doing something."
If you are 100% sure that you call this form other than UI thread, you can throw away that IF and just call dispatcher directly.
MyForm.Dispatcher.Invoke( mydelegate, params[] )
Or using some lambda instead of delegate or MethodInvoker ...
MyForm.Dispatcher.BeginInvoke( (Action)(()=>{ textbox.text = result; }), null);
And at all ... you can store (in form.load event for example) reference to UI Dispatcher to use in different class (some working class doing stuff on other )
If you creating some bigger UI stuff, my suggest for better UI and easier handling stuff like this is: ... consider some study of WPF and MVVM pattern and property change notifications.... it will give you very strong tool with "self updated" and very scalable UI and layers between datas, working threads and UI.
I am working on application which calls a function populate() on window_load
This function execution takes about 1 minute to complete. I wanna make this function to be called in separate thread.
I am using following code
Thread thread = new Thread(PopulateAndDrawGraph);
thread.Start();
in this function at last line is
nodeXlControl1.DrawGraph(true);
Here exception occurs
The calling thread cannot access this object because a different thread owns it.
what wrong is actually occurs
You are only allowed to access UI controls from within the same thread that created the control, which is usally the UI thread itself.
You will need to change your code in a way that it becomes thread-aware.
Here is a fantastic article that was published in the MSDN magazine: Give Your .NET-based Application a Fast and Responsive UI with Multiple Threads, which will explain in great detail how you can do what you want to do.
The article is a little old, but the same principles still apply.
I guess that the newer C# language features - like the new async / await keywords - should make your task a little easier.
But keep in mind that the same old limitations for accessing UI controls still exist. There is no way around to understand the basics as descripbed in the article.
There are 2 ways to handle this, a correct way and another way:
1: If you want a good working solution then this should do the trick, ..
private void SetText(string text)
{
// InvokeRequired required compares the thread ID of the
// calling thread to the thread ID of the creating thread.
// If these threads are different, it returns true.
if (this.textBox1.InvokeRequired)
{
SetTextCallback d = new SetTextCallback(SetText);
this.Invoke(d, new object[] { text });
}
else
{
this.textBox1.Text = text;
}
}
msdn.microsoft.com/en-us/library/ms171728.aspx
2: but if you want a quick solution without guarantee that it will work properly, just set this variable:
Control.CheckForIllegalCrossThreadCalls = False
The problem is, that the any UI interaction has to occur in the main thread of the application. My advice is that you draw make the computation in the separate thread, but collect your results in an object. After the thread is finished you can extract the result from that object, and place it the nodeXlControl1.
Sadly i don't know the details about your objective, the sum of the solution is this.
If u can tell more details about this i may be able to further help you.
check this article (How to: Make Thread-Safe Calls) here out. It explains all the related items regarding cross thread calls. I also recommend that you look into the concept of "Task" in c#. Theres a very well written lib that helps you handle parallelism and similar concepts!
Since you are trying to access a UI element from a thread you need to call Invoke. So in PopulateAndDrawGraph you should have:
Invoke((Action)(() =>
{
nodeXlControl1.DrawGraph(true);
}));
You can't access the UI controls from any other thread except the thread which has created this control(you can access/change the UI control properties from the main UI thread only). Go through this link, i hope this makes you clear Cross-thread operation not valid
I have used BackgroundWorker class in c#.
Recently decided to write a "quick" windows form app to tag my MP3 files. Not done anything with parallelism since .Net 3.0, so I'm looking at the Parallel.ForEach method to deal with the UI locking I get when I'm using a standard foreach statement. Here's an excerpt:
var i = 1;
var files = new List<string>(); // File list is populated using recursive method.
foreach(var f in files) {
// Add a row
var row = dgvList.Rows[dgvList.Rows.Add()];
// Update label
lblSummary.Text = string.Concat("Processing... ", i);
// Do things with row
// Increment progress bar
progressBar.PerformStep();
i++;
}
I've figured out the simple usage of Parallel.ForEach(), but I'm not sure I should be using that particular method to update the UI? Any suggestions?
You shouldn't use Parallel Libraries from your UI thread. The parallel library runs a group of tasks on multiple threads so you shouldn't write any UI related code inside it.
What you should do is move your business logic to background tasks and update the UI using dispatcher that will execute it on UI thread
as MSDN says
It is important to keep your application's user interface (UI) responsive. If an
operation contains enough work to warrant parallelization, then it likely should not
be run that operation on the UI thread. Instead, it should offload that operation to
be run on a background thread. For example, if you want to use a parallel loop to
compute some data that should then be rendered into a UI control, you should consider
executing the loop within a task instance rather than directly in a UI event handler.
Only when the core computation has completed should you then marshal the UI update back
to the UI thread.
and most importantly if you try to update UI thread from Paralle.Foreach
If you do run parallel loops on the UI thread, be careful to avoid updating UI
controls from within the loop. Attempting to update UI controls from within a parallel
loop that is executing on the UI thread can lead to state corruption, exceptions,
delayed updates, and even deadlocks, depending on how the UI update is invoked
You should be very careful with thread-safety.
You should be make sure to lock any object you are using, and unlock it appropriately.
Otherwise, there should be no problem I know of using Parallel.ForEach for UI.
EDIT: you can set Form.CheckForIllegalCrossThreadCalls=false to disable check for thread-safety.
Here's some documentation: http://msdn.microsoft.com/en-us/library/system.windows.forms.control.checkforillegalcrossthreadcalls.aspx
This will work, but it is dangerous, because then you need to care about your thread-safety by yourself.
A better way to deal with this is to use the invoke-pattern for the UI-logic, but then parallelism will suffer, as the UI operation itself will be called on the UI thread.
It is, however, the safe way to do things.
Documentation: http://msdn.microsoft.com/en-us/library/ms171728.aspx
OK, I found the best way to achieve this is by running something like this:
// Kick off thread
Task.Factory.StartNew(delegate{
foreach(var x in files) {
// Do stuff
// Update calling thread's UI
Invoke((Action)(() => {
progressBar.PerformStep();
}));
}
}
I actually updated my code to populate a List within the foreach loop, then assign that to the daragrid via .DataSource, instead of working with the .Rows collection directly. Should have done that from the start really :)
How do you implement busy waiting in a not total inefficient way? I am facing the issue that I can load the data of my model only in a pull manner, which means I have to invoke getXYZ() methods in a continuous way.
This has to happen not fast enough for user interaction, but fast enought, that when a state in the GUI is changed, the model can be noticed and the new state is received by the getXYZ() methods.
My approach simply be:
while (c.hasChanged()) {
Thread.sleep(500);
}
updateData();
Are there better mechanisms?
Your problem seems to be solvable with Threading.
In WPF you can do:
Thread t = new Thread((ThreadStart)delegate() {
while (true) {
Thread.sleep(500);
if (c.hasChanged())
Dispatcher.Invoke((Action)delegate() {updateData();});
}
}).Start();
In WinForms
Thread t = new Thread((ThreadStart)delegate() {
while (true) {
Thread.sleep(500);
// this must derive from Control
if (c.hasChanged())
this.Invoke((Action)delegate() {updateData();});
}
}).Start();
There may be missing parameters to Invoke (which is needed to execute the code on the calling UI thread) but I'm writing this from my brain so no intellisense at disposal :D
In .NET 4 you can use TaskFactory.StartNew instead of spawning a thread by yourself.
In .Net <= 4, you could use the TreadPool for the thread.
However I recall you need this to be run at once because you expect it to be there checking as soon as possible and the thread pool won't assure you that (it could be already full, but not very likely:-).
Just don't do silly things like spawning more of them in a loop!
And inside the thread you should put a check like
while (!Closing)
so that the thread can finish when you need it without having to resort to bad things like t.Abort();
An when exiting put the Closing to true and do a t.Join() to close the checker thread.
EDIT:
I forgot to say that the Closing should be a bool property or a VOLATILE boolean, not a simple boolean, because you won't be ensured that the thread could ever finish (well it would in case you are closing the application, but it is good practice to make them finish by your will). the volatile keyword is intended to prevent the (pseudo)compiler from applying any optimizations on the code that assume values of variables cannot change
It's not clear from your post exactly what you are trying to do, but it sounds like you should put your model/service calls on a separate thread (via Background worker or async delegate) and use a callback from the model/service call to notify the UI when it's done. Your UI thread can then do busy things, like show a progress bar, but not become unresponsive.
If you are polling from a GUI, use a (WinForms) Timer.
If this is some kind of background process, your Sleep() may be the lesser evil.
Explicit busy waiting is evil and must be avoided whenever possible.
If you cannot avoid it, then build your application using the Observer design pattern and register the interested objects to an object which performs the polling, backed by a thread.
That way you have a clean design, confining the ugly stuff in just one place.