I have been googling around for about an hour, and I still don't found any solution.
I simply try to set the maximum value of a progressbar from another thread. So I found the Control.Invoke method. I've been going ahead and implement it:
Now, when I debug my App it simply stucks at the this.Invoke line. The UI comes up, and it is frozen. So I was going ahead and google that out, and it told me to use this.BeginInvoke(). I implemented it, and I was fine, the UI don't freeze.
Thats quiet nice, but in fact the maximum value of my progress bar didn't change :(
What am I doing wrong?
EDIT: Maybe that helps: I am using Parallel.Invoke(); to manage my thread ...
Control.Invoke will only block when it is called on a worker thread and the UI thread is blocked.
The code you posted is correct. You must be blocking the UI thread somewhere else.
I use something similar below in my application which I use to update the actual value for the progress bar. I have changed it a bit from your example. Give it a whirl and see if it helps :)
public void SetMax(int value)
{
if (this.ProgressBar_status.InvokeRequired)
{
this.BeginInvoke(new Action<int>(SetMax), value);
return;
}
this.ProgressBar_status.Maximum = value;
}
I would suggest it is better to use Background worker component which supports reporting progress in the progress bar including other features rather than to call invoke and BeginInvoke. You can find more details about background worker at below MSDN link:
http://msdn.microsoft.com/en-us/library/c8dcext2.aspx
I had the same problem and thanks to Nicholas' answer I realised I had fallen into the same trap in a GUI app to debug a class used in a windows service. The service class runs most of it's code in a thread. The thread was calling back to a logging procedure when it stopped. I was stopping it using a button, and the logging used invoke to update a textbox. The problem was so simple I kicked myself - the invoke was waiting for the button-click to finish, which was waiting for the class to stop which was waiting for invoke to log that it was stopping (repeat until task-manager end process). Solved by creating a thread in the stop button click, with a threadproc to stop the service class. This meant I had to put more code to update form after the stop in another invoke from the new thread, but that worked ok as it wasn't waiting for the main form thread.
In my case, mistake was using join() after starting thread.
join() prevents main thread from execution of codes before child thread completion.
I removed join() command and moved codes after join() to thread and everything worked fine.
Related
I am using an external component which periodically shoots events from a worker thread. In my event handler I use a Dispatcher to invoke some method on the main thread. This works nicely...
private void HandleXYZ(object sender, EventArgs e)
{
...
if(OnTrigger != null)
dispatcher.Invoke(OnTrigger, new TimeSpan(0, 0, 1), e);
}
However, when the program shuts down and the external component Dispose()s, the program sometimes hangs (and can only be seen and killed in the task manager).
When I look at what is happening it looks like "the component" is waiting for the event to return on the main thread (it stays in the Dispose() method), while the worker thread waits for the dispatcher to invoke the mentioned call to the main thread (it hangs in the dispatcher.Invoke-line).
For now I solved the shutdown problem by adding a timeout to the Invoke, which seems to work but feels wrong.
Is there a cleaner way to do something like this? Can I force the main thread to take some time for jobs from other threads before shutting down?
I have tried to "disconnect" the event before shutting down, but that does not help, because the dispatcher is(could be) already waiting, when the program start to shut down...
PS: external component means here that I do not have access to the source code...
Yes, this is a common source of deadlock. It hangs because the dispatcher exited the dispatcher loop it won't respond to Invoke requests anymore. A quick cure is to use BeginInvoke instead, it doesn't wait for the invoke target to finish executing. Another quickie is to set the worker thread's IsBackground property to True so the CLR will kill it.
These are quick fixes and they may well work for you. Certainly on your dev machine, but if you have a nagging feeling that it may still go wrong then you're right, not observing a deadlock or threading race does not prove they are not present. There are two "good" ways to do it completely safely:
don't allow the main thread to exit until you are sure that the worker thread terminated and can no longer raise events. This answer shows the pattern.
terminate the program forcefully with Environment.Exit(). This is very crude but very effective, a sledgehammer you'll only reach for when you have a heavily threaded program where the UI thread is only second citizen. Odd as this may sound as a suitable approach, the new C++ language standard has elevated it to a supported way to terminate a program. You can read more about it in this answer. Do note how it allows for cleanup functions to be registered, you'll have to do something similar with, say, the AppDomain.ProcessExit event. Focus on the first bullet before you do this.
As for the event subscriptions, it is indeed a good idea to clean them up when you know that a particluar object is not needed anymore. Otherwise you would risk creating memory leaks. You might also want to have a look at the weak event pattern (MSDN).
Regarding the deadlock itself, without knowing your code, we can only guess.
I do not see the HandleXYZ() as a culprit, I would rather check your IDisposable() implemntaion. Have a look at the MSDN documentation and compare it to your implementation.
I suppose that somewhere in there in your implementation some method calls are made that depend on the timing of the GarbageCollector, which is indeterministic: Sometimes it may work out in your case, sometime it may not.
When I run the program in one fast computer, the ProgressBar and a Label(that write the progress too) gets perfectly updated. When I run it on a weak computer (like PIV or old c2d) the ProgressBar and the form stay freezed (but the program run until it finishes).
How can I resolve that? With background worker?
If you're using a progress bar, I'm guessing whatever the task is is definitely long enough to warrant a background/worker thread. There are lots of options (BackgroundWorker, spinning up your own thread, etc). BackgroundWorker is probably the easiest.
Yes, you should put your processing into a background thread. Using a background worker is a good idea, because you can simply update the controls from its ProgressChanged event.
There are some methods that allow the UI to be refereshed in long-running tasks.
1- run the task in another tread/in an anychronous method call and then using this.Invoke to change the progressbar.
2- Force the UI to refresh at some points in the task by calling Application.DoEvents() in winforms for instance.
Ok, I know this is bad program design, and I'll probably get around to fixing it later, but I'm looking for a quick fix...
I have a C# program that starts a thread that does some work, then in the main thread it starts listening for user input to manually kill the worker. The pseudo-code looks like this:
WorkerClass worker = new WorkerClass();
worker.Start(); //function that starts a new worker thread.
while(!Console.ReadLine().ToUpper().Equals("STOP")){}
worker.Join(); //function that cleanly stops the worker thread.
This works just fine, and originally the worker would always just hang out and continually do stuff, so it made sense to just wait for me to type "stop". However, I've since modified the worker thread so that it eventually reaches the end of it's tasks, and it knows it. Since there's nothing else happening, I'd like the main thread to stop too, but it's still waiting for input from the console. So, is there anyway I can enter text from the worker thread that's read as console input in the main thread?
I do want to keep the ability to manually stop the worker cleanly, so just changing the while statement to check for the worker completion instead of console input isn't really an option.
Rather than doing that, why not have your worker register an event, once the event is raised, you can then kill your loop and exit the application.
I have a situation in which I want a thread to process some sequential logic. This thread would need to interact with the main thread on occasion in order to update user input. But it should continue running otherwise without bothering the main thread. I am hopping to do this in an event-driven manner, so that the main thread doesn't have to pole the other thread for interrupts. What is the best way to do this? Is there an event-driven technique to communicating between threads much like there is in MFC?
I am using Visual Studio 2008 and (obviously) the .Net 3.5 framework.
Use the BackgroundWorker component.
Here you can find the best and complete tutorial about threading in C#, with code samples and examples.
AutoResetEvent and ManualResetEvent might be what you are after. Basically your main thread would wait using the various Wait methods of these classes until you signal from your other thread using the Set method. Then your wating thread will resume and continue with whatever comes afer Wait.
This is as good as it gets for an event-style. You have to wait and listen to receive an react on an event. How else are you supposed to stop your thread work in case you get an event gracefully? This is not possible with threads in general in any language.
Your only other possibility is frequent interrupting and polling.
Have a look at .Net Reactive Extensions IObservable and in particular the SubscribeOn and ObserveOn extension methods.
ObserveOn is where the work is done ( your background thread ), SubscribeOn is where the notifications go ( your UI thread ).
If you are using the BackgroundWorker you can raise a Progress event.
Here's an example on how to update a progress bar.
Ah ha! there is an event-driven way to do it. I borrowed the Dispatcher from WPF. I just give the spinning thread access to the main thread's CurrentDispatcher I let the thread spin and when it needs attention it invokes a delegate on the Dispatcher and sleeps waiting for the main thread to interrupt it. I know I could use Invoke instead of BeginInvoke, but I needed to use the interrupt because the method that restarts the worker thread is not a synchronous part of the dispatched delegates stack.
For better or worse, here is my code:
private void Run()
{
while (true)
{
...
// Need attention from the main thread
// "_main" is the main thread's Dispatcher instance.
_main.BeginInvoke(new MyEventHandler(OnNeedsAttention), this, new MyEventArgs(...));
try
{
Thread.Sleep(Timeout.Infinite);
}
catch (ThreadInterruptedException) { }
}
}
I currently have a thread that listens for data from the network and then runs rules on it. I then want to pass the data to the GUI. I am worried about having a deadlock in the GUI. I cant figure out were to put the mutexes on the GUI side. I am also using c# and dotnet 3.5.
What I have come up with is
1) Using a timer to create an event and dump the thread. Worried about performance.
2) Use an intermediary event to copy the data to GUI.
3) Dig in and figure out thread safe way of using GUI.
What do you think is best way to proceed?
Edit: Here is the solution I am using. I pass in the changed element and then protect the big object with a mutex. I use helper function to switch threads using InvokeRequired then BeginInvoke with a delegate. Pulled from reading the answers and then following links until reaching Threading in Windows Forms by Jon Skeet.
delegate void UInt32ParameterDelegate(UInt32 n);
public void UpdateLocation(UInt32 n)
{
if (InvokeRequired)
{
// We're not in the UI thread, so we need to call BeginInvoke
BeginInvoke(new UInt32ParameterDelegate(UpdateLocation), new object[] { n });
return;
}
// Must be on the UI thread if we've got this far
this.engine.location.UpdateBusy.WaitOne();
// do the work in here
this.engine.location.UpdateBusy.ReleaseMutex();
}
Synchronization is very easy in Windows Forms. You can call Control.Invoke() in the background thread. The thread will stall until the delegate has finished running on the UI thread. No sync required at all.
If stalling the thread is a problem, use Control.BeginInvoke(). You'll have to protect the object(s) you pass to the delegate with a lock if the thread might alter them while it continues running. That's rarely the case in a producer-consumer scenario, the thread can simply create new objects.
Do make sure that you don't Invoke() too often. Do it more frequently than about 1000 times per second and the UI thread will stop pumping Windows messages, being bogged down by handling the invoke requests. Since it is human eyes you're trying to please, invoking more than about 25 times per second is just wasted effort. Pool intermediate results in a collection object.
I hope I understand your problem correctly.
After the background thread reads the data and does whatever it wants, it should use Invoke to call a method on the GUI thread. That method would update anything that should be updated in the GUI.
Never read from the network on the GUI thread. It's only a matter of time before your application runs during a network outage and your GUI hangs as a result. This will really frustrate your users.
In your situation I think the best approach is to have a background thread complete the read operation. Then take the resulting data and move it back to the GUI thread via a SynchronizationContext Post or Send method.
you should just pass an event from your network thread to your UI thread.
then cross threads using begininvoke so you don't get a cross thread exception.
Need help getting info across a UI thread and another thread in C#
You could use a backgroundworker that will process the datareading in a background thread and when it's done you can end the backgroundworker triggering it's RunWorkerCompletedEventHandler. In the RunWorkerCompletedEventHandler you can update your GUI thread with the result.
Isn't easier to just throw a delegate who raise an event that inform the form to refresh itself?