Mutual exclusive operations in UI thread with Dispatcher.PushFrame and Application.DoEvents - c#

The situation
I'll try to explain my Problem with a small example. I have a class that manages a view-stack. Replaces views shows and initializes them etc.
class ViewManager()
{
void ReplaceView()
{
RemoveView(...);
InitializeView(...); // this code may call Application.DoEvents()
AddNewView(...);
}
void ShowModalView()
{
ShowView();
Dispatcher.PushFrame()
....
// wait until view can be removed
RemoveView();
}
void RemoveView()
{
...
}
// ... more functions
}
Because the ViewManager does a lot with UI elements, other Threads uses the ViewManager through Dispatcher.Invoke.
Dispatcher.Invoke(new Action(() => m_viewManager.Remove(someView)));
If now multiple threads Invoke actions on the ViewManager, and one of them calls deep down somewhere in the code Application.DoEvents or DispatcherPushFrame, a second MessageLoop is spawned that will invoke another method o n the view Manager.
The Problem:
ShowModalView is called and calls PushFrame.
During ShowModalView another thread calls ShowModalView or ReplaceView.
Because the new message loop executes all tasks queued to the dispatcher this method are also executed.
Therefore two methods of the ViewManager are executed "at the same time" - or better because it is the same thread - nested in each other.
Locking inside the ViewManager is useless, because it is all the same thread. A semaphore might freeze the UI thread, because during the Message loop of the "ShowModalView" another thread can invoke ShowModalView on the dispatcher and that will freeze the UI thread.
The Questions:
During the "ShowModalView" the UI thread should handle input / paint etc but should not handle other tasks invoked through "Dispatcher.Invoke" Is this possible?
Do you have other Ideas to solve this problem?
Thank you for your hints and answers
Manuel
EDIT:
One solution might be to get rid of all DoEvents and PushFrame code. This is very hard to achieve but probably the only right solution. This post explains a part of my Problem
Use of Application.DoEvents

As Servy said, get rid of Application.DoEvents() and Dispatcher.PushFrame is the only clean solution. Sometimes this will cause a lot of refactoring but it is worth the effort.

Related

Updating controls in Main Thread using EventHandler

I'm using this to update a control in the main thread from another thread:
private void ShowHourGlassSafe(bool visible)
{
this.Invoke((EventHandler)((s, ev) => pictureBoxHourGlass.Visible = visible));
}
I wonder what are the implications of doing it this way or if is there any risk this is going to fail?
From the many examples are there for the same thing I could not find one like this.
It could be that it's simply wrong?
Well, you've picked a rather odd delegate to choose, as you've chosen one that has two parameters despite the fact that none are needed nor will be provided. I don't know if that will cause it to break, but it's certainly doing nothing to help. You're most likely best off using a delegate that takes no parameters and returns no values, such as:
private void ShowHourGlassSafe(bool visible)
{
this.Invoke((MethodInvoker)(() => pictureBoxHourGlass.Visible = visible));
}
Other than that, the fundamental concept of what you're doing is perfectly fine.
Typical problems with this kind of code:
You'll deadlock if the UI thread is doing something unwise like waiting for the thread to complete. There's no point in using Invoke, that blocks the worker thread for no benefit, just use BeginInvoke. Solves the deadlock potential and the unnecessary delay.
You'll crash when the UI was closed and pictureBoxHourGlass was disposed. Ensuring that the thread is no longer running before allowing the UI to close is very commonly overlooked. Just displaying an hour glass isn't enough, you also have to take countermeasures to prevent the user from closing the UI. Or otherwise interlock it with a way to cancel the thread first
The user will typically be befuddled when an hour glass shows up without him doing anything to ask that something gets done. The 99% correct case is that you display the hour glass with code in the UI thread and then start the thread. And hide it again when the thread completes. Easiest to do with the BackgroundWorker or Task classes, they can run code on the UI thread after the job was done.
Favor the Action delegate types for consistency:
private void ShowHourGlassSafe(bool visible) {
this.BeginInvoke(new Action(() => something.Visible = visible));
}

How can a function be triggered with an event?

I have an application wherein I would like a function to be executed in the same thread when an event is fired. For example:
SomeCode()
{
// Do something...
// Fire event to run SomeOtherCode().
}
SomeOtherCode()
{
// Do something else...
}
I do not want to simply call the function because it will hold things up. SomeOtherFuction() needs to be executed in the same thread because it needs to access the form controls, and I need it to begin execution from an event trigger firing. I am using Microsoft Visual C# 2008 Express Edition. Thanks.
::: EDIT:::
Additional Details: The bottom line is that the contrustor of my form application is taking far too long to complete, and it is causing a significant delay, from when the user launches the application to when the application window appears on the display. This is not a problem on faster computers, but on slower computers it is a big problem. I need to exit the contrustor as soon as possible, thus allowing the framework to draw the application window, and continue initialization outside the constructor. (All essential items would still be initialized inside the constructor.)
An event-triggered function call would be ideal. I would prefer not to use a timer. Interlacing the affected code with Invokes is impractical in my situation and would require much more time to implement than I have to work on this. A simple example of an event-driven function call is all I'm really looking for. Thanks.
From your posts it's seems like you're confusing a few issues. The standard pattern in .Net is for events to run synchronously. The following lines are essentially identical in terms of when they execute.
Option #1
SomeCode();
SomeOtherCode();
Option #2
SomeEvent += delegate { SomeOtherCode(); }
...
SomeCode();
SomeEvent(this,EventArgs.Empty);
If you want to unblock the UI thread and run the code later you'll need to use some mechanism to delay the running of the SomeOtherCode function. The easiest way to do this in a WinForms application is to use a WinForms Timer instance. This will raise an event on the UI thread at a later point in time that you can respond to. It also won't block the UI thread during this time allowing your form to continue processing.
You seem to be asking to run SomeOtherCode() later.
You can call BeginInvoke (either from the UI thread or from any other thread) to queue a function to run during the next message loop:
BeginInvoke(new Action(SomeOtherCode));
It seems that you would want to add an event to the class that exposes the SomeCode method. Then, the class that implements the SomeOtherCode method would attach an event handler that calls the SomeOtherCode method.
It's completely viable to have this done in one class, in case you have some sort of state model where you want to add/remove the call depending on some other logic.
I think you want to put SomeOtherCode into a Task or BackgroundWorker, which would then synchronize with the UI thread to send it updates.
I recently posted on my blog a class that makes updating the UI from a Task as easy as from a BGW. I do recommend using Task rather than BackgroundWorker.
Simialr to what Stephen said, I would recommend that you move as much of that initialization code to a background thread or task. Let the background thread do as much work as possible, then send the necessary window updates to your UI thread via Action<>'s. Here's some quick psuedo-sample code:
protected void LoadMyListInBackground(object state)
{
List<string> myList = Databse.FetchMyList(myParameters); // This take a while, so the UI thread isn't waiting
ShowMyList(myList);
}
protected void ShowMyList(List<string> theList)
{
if(InvokeRequired)
Invoke(new Action<List<string>>(ShowMyList, theList);
else
{
foreach(string item in theList)
myListBox.Items.Add(item);
}
}
In this example the UI thread is free to keep drawing your window while the background thread does the lengthy database work. The problem is, even if you fire an event outside of your constructor, and that event occurs on the UI thread and takes a long time, the user might see the window but that window is going to 'freeze' and possibly appear to be 'crashed' to the user. This technique prevents that and provides a better user experience.

How do you notify a parent thread that all child threads have terminated?

I have a console app that I'm porting to WPF. The application has 3 worker threads, that are all joined to the main thread before some output results are printed to the screen. My understanding is that, if I try and do the same thing in a WPF application, the GUI will be blocked and will not be reponsive to the user. How then can I notify the parent thread that all the threads have completed their work? I think the solution is going to involve delegates and events (or maybe BackgroundWorker?), but it was not clear to me how to get the callback invoked when the thread terminated.
Original Code:
foreach (Thread t in threadList)
{
t.Start();
}
foreach (Thread t in threadList)
{
t.Join();
}
// print some results here
If you are using three BackgroundWorkers, you can use the event RunWorkerCompleted to notice that one of the workers is completed: Before starting the workers set a counter to 3 then decrement and check this counter in the method called by RunWorkerCompleted if it hits 0 you are finished.
You should use three BackgroundWorkers.
You can then handle their RunWorkerCompleted events to find out when the operations finish.
Take a look at this article in MSDN magazine that gives you an example on using BackgroundWorker. Start at Figure 7.
Depends on what you would like to accomplish. What form of communication are you trying to facilitate?
If I were to guess, what you really want is to simply report [or display] your worker results in your application. If this is the case, then in a typical WPF application you have a view model, say
public class AwesomeViewModel : INotifyPropertyChanged
{
// if small fixed number, otherwise, you could use
// an ObservableCollection<T>
public string WorkerResultA { ... }
public string WorkerResultB { ... }
public string WorkerResultC { ... }
}
which is data-bound to your WPF controls. You can simply pass a reference of your view model to each worker thread and they update the class without requiring blocking\waiting on Gui thread. In this manner, each worker reports its results when it completes without intervention from anyone else. This is optimal.
Of course, if you go ahead and do just this, you run into another completely different issue. Which, fyi, is resolvable via Dispatcher. One possible solution here.
As for BackgroundWorker versus explicit Thread control, that is up to you. There are advantages to both, but remember you already have functional code written. That, and in my personal opinion, BackgroundWorker isn't particularly useful.
If you really absolutely positively must implement a more sophisticated synchronization model, then I highly recommend you brush up on ManualResetEvent its cousin AutoResetEvent, Semaphore, keyword lock and concurrent programming in general. Sorry, no shortcuts there :)
Hope this helps!
If you just want to poll the worker threads, you could use something like
bool threadWasDone = thread.Join(0);

How to Make Sure UI is Responsive Using BackgroundWorker

Is BackgroundWorker in c# Thread Safe?
The reason I ask this is because I get a
Controls created on one thread cannot
be parented to a control on a
different thread
exception with it. This is my DoWork event code:
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
var openFile = document.Open(MyFileName);
e.Result = openFile;
}
where document is an UI control that is initialized when the parent form is created. During Open method various properties in document will be filled.
I tried to change the code to invoke, yet the same problem persists. i.e,
document.GetType().GetMethod("Open)".Invoke(document, new object[]{MyFileName})
will yield the same error as the above.
Any idea how to manipulate the document control? In other words, how to make the above code work?
Edit: It was suggested that I use Control.Invoke, but it still didn't work ( both of the threads hanged). This is the code I tried:
private delegate bool OpenFile(string filePath);
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
OpenFile oF = new OpenFile(document.Open);
var openFile = Invoke(oF, MyFileName); // it doesn't really matter whether I use BeginInvoke or Invoke, or other Control.Invoke, the end result is the same. Both the main thread hosting the document and the thread that launches the UI hanged.
e.Result = openFile;
}
It isn't the thread that's the problem it's the fact that it's trying to call a method on a UI control. In both WPF and WinForms controls can only be called on the UI thread (of which there is typically one). You don't say which you are using but you need to call the Control.Invoke method for WinForms or Dispatcher.Invoke for WPF.
The Invoke() reflection method you show will actually invoke the method on the current thread.
You can either invoke as Mehrdad Afshari suggested, or you can make use of the bgw's progress event which comes back on the UI thread. Or the work completed event which also comes back on the UI thread. The difference between the two is WorkCompleted is fired only once at the end. Progress is fired by you from DoWork.
While it's unclear to me what you exactly mean by thread-safety of a BackgroundWorker, the problem is not that object; Windows Forms controls are designed to be manipulated on a single thread (the UI thread). You should not manipulate Windows Forms objects on different threads. You can invoke actions in the UI thread from other threads by using the Control.Invoke method (the Invoke method you are currently using is provided by reflection and is totally unrelated to this problem):
Invoke(new Action(MethodToRunInUIThread));
void MethodToRunInUIThread() {
// do stuff here.
}
By the way, it doesn't make sense to use a background worker if all you are doing is manipulating UI objects.
If that functionality of the UI Control takes that long to execute, there may not be much you can do. "Freezing" occurs when a long-running operation happens on the UI thread, and if that function of the control was not specifically made thread-safe, it must be run on the main thread.
Normally, you'd want to separate the "document" functionality away from the control that displays it. This way, your document could be loaded on a separate, independent thread and be displayed later when ready. Otherwise, the control itself would have to implement a multi-threaded load routine to slow loading freezes.
Since you've specified this is a third party control in your comments, you may be out of luck here.
BackgroundWorker is a thread based structure. The thread-safety matter is about functions when doing simultaneous tasks. Maybe what you ask for is about winforms controls which are accessed through a unique thread, that of the user interface thread.
You need to use Control.BeginInvoke() in DoWork. This executes the delegate asynchronously and so will ensure the calling thread will not "hang".
Control.Invoke() will execute the delegate on the other thread also, but will cause the calling thread to wait for it to complete.
Generally in Windows Forms you are better off using Control.BeginInvoke() wherever possible to help avoid deadlocking between threads that can occur when one thread waits for another, as with Control.Invoke().
If the "document" object inherits from System.Windows.Forms.Control, you can simply call document.BeginInvoke(myDelegate).
However if it is actually some other component that encapsulates GUI controls, it may expose some way to call BeginInvoke. Check the documentation (if any). If there is no such ability, then unfortunately it is probably just not designed to support multi-threaded applications.
It looks like you are confused about the various Invoke/BeginInvoke types (understandable). This earlier question: What is the difference between Invoke and BeginInvoke? and Jon Skeets answer should help clarify things.
#Graviton, a related task with an answer is found here. The person was using BackgroundWorker to update a textbox, same concept applies (yours is only a single worker thread).

How can I check if a function is being called on a particular Thread?

If I have Thread A which is the main Application Thread and a secondary Thread. How can I check if a function is being called within Thread B?
Basically I am trying to implement the following code snippit:
public void ensureRunningOnCorrectThread()
{
if( function is being called within ThreadB )
{
performIO()
}
else
{
// call performIO so that it is called (invoked?) on ThreadB
}
}
Is there a way to perform this functionality within C# or is there a better way of looking at the problem?
EDIT 1
I have noticed the following within the MSDN documentation, although Im a dit dubious as to whether or not its a good thing to be doing! :
// if function is being called within ThreadB
if( System.Threading.Thread.CurrentThread.Equals(ThreadB) )
{
}
EDIT 2
I realise that Im looking at this problem in the wrong way (thanks to the answers below who helped me see this) all I care about is that the IO does not happen on ThreadA. This means that it could happen on ThreadB or indeed anyother Thread e.g. a BackgroundWorker. I have decided that creating a new BackgroundWorker within the else portion of the above f statement ensures that the IO is performed in a non-blocking fashion. Im not entirely sure that this is the best solution to my problem, however it appears to work!
Here's one way to do it:
if (System.Threading.Thread.CurrentThread.ManagedThreadId == ThreadB.ManagedThreadId)
...
I don't know enough about .NET's Thread class implementation to know if the comparison above is equivalent to Equals() or not, but in absence of this knowledge, comparing the IDs is a safe bet.
There may be a better (where better = easier, faster, etc.) way to accomplish what you're trying to do, depending on a few things like:
what kind of app (ASP.NET, WinForms, console, etc.) are you building?
why do you want to enforce I/O on only one thread?
what kind of I/O is this? (e.g. writes to one file? network I/O constrained to one socket? etc.)
what are your performance constraints relative to cost of locking, number of concurrent worker threads, etc?
whether the "else" clause in your code needs to be blocking, fire-and-forget, or something more sophisticated
how you want to deal with timeouts, deadlocks, etc.
Adding this info to your question would be helpful, although if yours is a WinForms app and you're talking about user-facing GUI I/O, you can skip the other questions since the scenario is obvious.
Keep in mind that // call performIO so that it is called (invoked?) on ThreadB implementation will vary depending on whether this is WinForms, ASP.NET, console, etc.
If WinForms, check out this CodeProject post for a cool way to handle it. Also see MSDN for how this is usually handled using InvokeRequired.
If Console or generalized server app (no GUI), you'll need to figure out how to let the main thread know that it has work waiting-- and you may want to consider an alternate implementation which has a I/O worker thread or thread pool which just sits around executing queued I/O requests that you queue to it. Or you might want to consider synchronizing your I/O requests (easier) instead of marshalling calls over to one thread (harder).
If ASP.NET, you're probably implementing this in the wrong way. It's usually more effective to use ASP.NET async pages and/or to (per above) synchronize snchronizing to your I/O using lock{} or another synchronization method.
What you are trying to do is the opposite of what the InvokeRequired property of a windows form control does, so if it's a window form application, you could just use the property of your main form:
if (InvokeRequired) {
// running in a separate thread
} else {
// running in the main thread, so needs to send the task to the worker thread
}
The else part of your snippet, Invoking PerformIO on ThreadB is only going to work when ThreadB is the Main thread running a Messageloop.
So maybe you should rethink what you are doing here, it is not a normal construction.
Does your secondary thread do anything else besides the performIO() function? If not, then an easy way to do this is to use a System.Threading.ManualResetEvent. Have the secondary thread sit in a while loop waiting for the event to be set. When the event is signaled, the secondary thread can perform the I/O processing. To signal the event, have the main thread call the Set() method of the event object.
using System.Threading;
static void Main(string[] args)
{
ManualResetEvent processEvent = new ManualResetEvent(false);
Thread thread = new Thread(delegate() {
while (processEvent.WaitOne()) {
performIO();
processEvent.Reset(); // reset for next pass...
}
});
thread.Name = "I/O Processing Thread"; // name the thread
thread.Start();
// Do GUI stuff...
// When time to perform the IO processing, signal the event.
processEvent.Set();
}
Also, as an aside, get into the habit of naming any System.Threading.Thread objects as they are created. When you create the secondary thread, set the thread name via the Name property. This will help you when looking at the Threads window in Debug sessions, and it also allows you to print the thread name to the console or the Output window if the thread identity is ever in doubt.

Categories

Resources