Forcing code execution on main thread - c#

How can I force a section of code to be executed on my main thread?
This is why I'd like to know:
I have a custom created message box that at times gets shown from a thread that is not the main thread. However, when the message box constructor is called I get an InvalidOperationException saying "The calling thread must be STA, because many UI components require this." This makes sense, UI elements need to be handled on the main thread.
My MessageBox.ShowMessage(...) function is a static function that creates an instance of my custom message box and shows it. Is there a something I could put in ShowMessage that would force the message box to be created and shown on the main thread? Elsewhere in my code I use the Control.BeginInvoke to handle similar issues, but since it is a static function there is no already existing UI element for me to call BeginInvoke on.
Do I have to call MessageBox.ShowMessage from with a Control.BeginInvoke? I'd prefer the BeginInvoke (or some equivalent) to be called from within ShowMessage.

There are a few options here:
make the second thread STA (you can only do this for your own Thread - not for ThreadPool threads) - via .SetApartmentState(ApartmentState.STA);
see if SynchronizationContext.Current is non-null; if so, use Send/Post
pass the form/control in as an ISynchronizeInvoke instance (may not apply to WPF - I'm not 100% sure)

Your thinking is right -- in order to get it to work properly, you're going to need to get it called from the main thread.
The simplest way? When you start your main form, save a reference in a static variable that is visible to your ShowMessage() call. Then, your ShowMessage can do the standard:
if(myForm.InvokeRequired)
{
myForm.Invoke(() => ShowMessage(arg1,arg2,arg3));
return;
}
.... other code here....

Instead of directly showing the message box, just send a message to your main thread, which signals the main thread to display a message box.

Related

Need second (and third) opinions on my fix for this Winforms race condition

There are a hundred examples in blogs, etc. on how to implement a background worker that logs or gives status to a foreground GUI element. Most of them include an approach to handle the race condition that exists between spawning the worker thread, and creating the foreground dialog with ShowDialog(). However, it occured to me that a simple approach is to force the creation of the handle in the form constructor, so that the thread won't be able to trigger an Invoke/BeginInvoke call on the form prior to its handle creation.
Consider a simple example of a Logger class that uses a background worker thread to log to the foreground.
Assume, also, that we don't want NLog or some other heavy framework to do something so simple and lightweight.
My logger window is opened with ShowDialog() by the foreground thread, but only after the background "worker" thread is started. The worker thread calls logger.Log() which itself uses logForm.BeginInvoke() to update the log control correctly on the foreground thread.
public override void Log(string s)
{
form.BeginInvoke(logDelegate, s);
}
Where logDelegate is just a simple wrapper around "form.Log()" or some other code that may update a progress bar.
The problem lies in the race condition that exists; when the background worker thread starts logging before the foreground ShowDialog() is called the form's Handle hasn't yet been created so the BeginInvoke() call fails.
I'm familiar with the various approaches, including using a Form OnLoad event and a timer to create the worker task suspended until the OnLoad event generates a timer message that starts the task once the form is shown, or, as mentioned, using a queue for the messages. However, I think that simply forcing the dialog's handle to create early (in the constructor) ensures there is no race condition, assuming the thread is spawned off by the same thread that creates the dialog.
http://msdn.microsoft.com/en-us/library/system.windows.forms.control.handle(v=vs.71).aspx
MSDN says: "If the handle has not yet been created, referencing this property will force the handle to be created."
So my logger wraps a form, and its constructor does:
public SimpleProgressDialog() {
var h = form.Handle; // dereference the handle
}
The solution seems too simple to be correct. I'm specifically interested in why the seemingly too simple solution is or isn't safe to use.
Any comments? Am I missing something else?
EDIT: I'm NOT asking for alternatives. Not asking how to use NLog or Log4net, etc. if I were, I'd write a page about all of the customer constraints on this app, etc.
By the number of upvotes, there are a lot of other people that would like to know the answer too.
If you are concerned that referencing Control.Handle relies on a side effect in order to create the handle, you can simply call Control.CreateControl() to create it. However, referencing the property has the benefit of not initializing it if it already exists.
As for whether this is safe or not assuming the handle is created, you are correct: as long as you create the handle before spawning the background task on the same thread, you will avoid a race condition.
My two cents: there's no real need to force early handle creation if the logging framework simply maintains a buffer of undisplayed log entries while the handle has not been created. It could be implemented as a Queue, or many other things. Messing with the order of handle creation in .NET makes me squeamish.
I think the only danger is decreased performance. Handle creation is deferred in winforms to speed things up. However, since it sound like this is a one-time operation, it doesn't sound costly, so I think your approach is fine.
You can always check the IsHandleCreated property of your form to see if the handle has been built yet; however, there are some caveats. I've been in a similar spot to yours, where winforms controls are being created/destroyed dynamically with lots of multithreading going on. The pattern we wound up using was quite a bit like this:
private void SomeEventHandler(object sender, EventArgs e) // called from a bg thread
{
MethodInvoker ivk = delegate
{
if(this.IsDisposed)
return; // bail out! Run away!
// maybe look for queued stuff if it exists?
// the code to run on the UI thread
};
if(this.IsDisposed)
return; // run away! killer rabbits with pointy teeth!
if(!this.IsHandleCreated) // handle not built yet, do something in the meantime
DoSomethingToQueueTheCall(ivk);
else
this.BeginInvoke(ivk);
}
The big lesson here is to expect a kaboom if you attempt to interact with your form after it has been disposed. Don't rely on InvokeRequired, since it will return false on any thread if the control's handle hasn't been created yet. Also don't rely solely on IsHandleCreated since that will return false after the control has been disposed.
Basically, you have three flags whose state will tell you what you need to know about the control's initialization state and whether or not you're on a BG thread relative to the control.
The control can be in one of three initialization states:
Uninitialized, no handle created yet
InvokeRequired returns false on every thread
IsHandleCreated returns false
IsDisposed returns false
Initialized, ready, active
InvokeRequired does what the docs say
IsHandleCreated returns true
IsDisposed returns false
Disposed
InvokeRequired returns false on every thread
IsHandleCreated returns false
IsDisposed returns true
Hope this helps.
Since you do create the window on the calling thread you can end up with deadlocks. If the thread that creates the window has no message pump running your BeginInvoke will add your delegate call to the message queue which will never be emptied, if you do not have an Application.Run() on the same thread which will process the window messages.
It is also very slow to send around window messages for each log message. It is much better to have a producer consumer model where your logging thread adds a message to a Queue<string> which is emptied by another thread. The only time you need to lock is when you enqueue or dequeue a message. The consumer thread can wait for an event with a timeout to start processing the next message when either the event was signaled or the timeout (e.g. 100ms) has elapsed.
A thread safe blocking Queue can be found here.

WPF/threading: Dispatcher static vs Dispatcher on a control?

I'm a bit confused in terms of the dispatcher. Say I'm on a background thread doing some kind of long operation. I'd like to update the ui thread I understand I do this through the dispatcher. My question is, do i call the dispatcher statically like: Dispatcher.BeginInvoke(mywork) ... Or on the control i want to update: mytextbox.Dispatcher.BeginInvoke(mywork)
It's worth noting that calling Dispatcher.BeginInvoke isn't a static call: it's an implicit this.Dispatcher.BeginInvoke. If you can use this call, you're likely writing your code from within a control or window already. In that case, you're probably safe to call either since most of the time there will be one UI thread per application.
The actual static call would be Dispatcher.CurrentDispatcher.BeginInvoke, which is not something you want to call (see my comment on Hasan Khan's answer for why).
EDIT: Calling Application.Current.Dispatcher is not a bad thing. (And, for clarity, it's an instance property, not a static - being called on a static/singleton instance of Application.) This property will return the Dispatcher for the thread that the app was created with, and typically that's the thread that the UI is created on aswell - so Application.Current.Dispatcher returns the same Dispatcher as myWindow.Dispatcher would.
The static call Dispatcher.CurrentDispatcher (that I warned against) returns a Dispatcher for the thread you call it from. If you call it from a background thread, you'll get a new Dispatcher created especially for that thread - which often isn't what's wanted.
First I think it is important to understand, that the Dispatcher is not designed to handle big background operations. It is designed to queue work on the UI thread of an object. Here is a worthwhile MSDN article about the .NET threading model and Dispatcher:
Threading Model, Overview and the Dispatcher
Saying that the standard way of implementing the Dispatcher.BeginInvoke method would be to call it on the control:
startStopButton.Dispatcher.BeginInvoke(
DispatcherPriority.Normal, new NextPrimeDelegate(CheckNextNumber)
);
Hope that helps!
While in most cases using either DispatcherObject.Dispatcher (all dependency objects and controls inherit from DispatcherObject, among others) or Application.Current.Dispatcher is the right thing to do, as there's usually only one UI thread, there can be multiple UI threads and different windows can use different dispatchers. In that case, it's important to update the control using its dispatcher. It's stored in in its Dispatcher property (inherited from DispatcherObject), any other control in this window and the window itself.

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 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 to start a UI thread in C#

I know I can start a new worker thread from with .NET. But how do I start a new UI thread (like in MFC)?
I don't mind if the solution is restricted to Windows boxes only; I also would like the solution to be purely .NET - no p/invokes to CreateThread, etc.
Any input appreciated.
Use Application.Run - it starts a message loop in the current thread. There are overloads to take a form to start with, or an application context, or neither. (If you want to do this for a new thread, you need to create the thread and start it in the normal way, and make it call Application.Run.)
If you are interested in using WPF, check out MSDN's article WPF's Threading Model, in particular the "Multiple Windows, Multiple Threads" section. It details what you need to do to create a new Dispatcher and show a window on a new thread.
If you're looking to create a new thread that is capable of creating and dealing with Window handles, then you can use the SetApartmentState function on the Thread object and set it to STA. You'll also likely need to call Application.Run inside the method for this thread in order to create your message loop. However, bear in mind that you're subject to the same cross-threading no-no's that you have in any other thread (ie, you can only interact with the handle for a control on the thread inside which it was created), so you can't do anything on your other UI thread without switching contexts.
Also you can do this:
delegate void MyProcHandler(object param1, object param2);
MyForm.Invoke
(
new MyProcHandler(delegate(object param1, object param2)
{
// some code
}),
null,
null
);

Categories

Resources