I've inherited code where BeginInvoke is called from the main thread (not a background thread, which is usually the pattern). I am trying to understand what it actually does in this scenario.
Does the method being called in the BeginInvoke get in line of messages that come down to the window? The docs say asynchronously, so that is my assumption.
How does the framework prioritize when to kick off the method called by BeginInvoke?
Edit: The code looks like this:
System.Action<bool> finalizeUI = delegate(bool open)
{
try
{
// do somewhat time consuming stuff
}
finally
{
Cursor.Current = Cursors.Default;
}
};
Cursor.Current = Cursors.WaitCursor;
BeginInvoke(finalizeUI, true);
This is happening in the Form_Load event.
edit
Now that we see the code, it's clear that this is just a way to move some initialization out of Form_Load but still have it happen before the user can interact with the form.
The call to BeginInvoke is inside Form_load, and is not called on another object, so this is a call to Form.BeginInvoke. So what's happening is this.
Form_Load passes a delegate to Form.BeginInvoke, this puts a message in the form's message queue that is ahead of all user input messages. It sets the cursor to a wait cursor.
Form_Load returns, and the rest of form initialization is allowed to complete, the form most likely becomes visible at this point.
Once the code falls into the message pump, the first thing is sees in the queue is the delegate, so it runs that.
as the delegate completes, it changes the cursor back to the normal cursor, and returns
profit!
original post below
I depends on the object that you call BeginInvoke on. If the object is derived from Control then Control.BeginInvoke will run on the thread that created the control. See JaredPar's answer.
But there is another pattern for the use of BeginInvoke. if the object is a delegate, then BeginInvoke runs the callback on a separate thread, one that may be created specifically for that purpose.
public class Foo
{
...
public Object Bar(object arg)
{
// this function will run on a separate thread.
}
}
...
// this delegate is used to Invoke Bar on Foo in separate thread, this must
// take the same arguments and return the same value as the Bar method of Foo
public delegate object FooBarCaller (object arg);
...
// call this on the main thread to invoke Foo.Bar on a background thread
//
public IAsyncResult BeginFooBar(AsyncCallback callback, object arg)
{
Foo foo = new Foo();
FooBarCaller caller = new FooBarCaller (foo.Bar);
return caller.BeginInvoke (arg);
}
This pattern is one reason that BeginInvoke is called from the main thread rather than from a background thread.
In the case BeginInvoke is called on a UI thread it will still go through the process of posting a Windows Message to the message queue where the message will wait to be processed. The delegate will run when the message is processed. This message is not prioritized in any way that's different than it being called from the background thread.
In this scenario I suspect the call looks like:
private void Button1_Click(object sender, ButtonClickEventArgs e)
{
Control.BeginInvoke(new MethodInvoker(()=> /* code etc. */));
}
What's happening is that some code will run on on a threadpool thread, and update the control on the thread that created the control whereas if Control.Invoke was used, some code would run on the thread that created the control, and update the control on that thread as well.
Prior to widespread BackgroundWorker use, you had to synchronize back to the UI thread before doing any operations on Controls created on the UI thread (i.e. pretty much every Control).
There's a pretty good reference example here down in the "Thread-Safe Calls to a Windows Forms Control" section.
Related
I am building an Windows Form-based app that listens on a port and when it receives a specific command, it opens a window (Form) that requests input.
My problem is that even though I am using a delegated method to open the window, only the window furniture/border is drawn. The contents of the form are not rendered at all.
From searching other answers on S.O., there seem to be two causes for this:
InitializeComponent() not being called
Trying to open the window from a non-UI thread
It appears that #2 is my problem. When I compare the ManagedThreadId in the form constructor and from the callback delegate, they are different.
As far as I can tell from the docs, the delegate should ensure that the callback is run on the UI thread.
Can anyone suggest why it isn't?
Below is a simplified version of what my code looks like.
The form
public wPrompt(bool silent, bool listen)
{
InitializeComponent();
// Thread.CurrentThread.ManagedThreadId returns 1
// Register a handler for scan requests received via the network
SocketListener.OpenFormRequest += OpenFormCommandHandler;
// Class that contains the code to open a socket and listen for commands
SocketListener.StartListening();
}
private void wPrompt_Load(object sender, System.EventArgs e)
{
// Thread.CurrentThread.ManagedThreadId returns 3
}
// The callback that gets called by the delegate
private void OpenFormCommandHandler()
{
// Thread.CurrentThread.ManagedThreadId returns 3
// Open the form
Visible = true;
}
The SocketListener class
class SocketListener
{
public delegate void OpenFormRequestEventHandler();
public static event OpenFormRequestEventHandler OpenFormRequest;
public static void StartListening()
{
// Thread.CurrentThread.ManagedThreadId returns 1
// Initialise and start worker thread
workerThread = new Thread(new ThreadStart(ListenThread));
workerThread.Start();
}
// A slightly modified version of the Synchronous Server Socket Example at
// https://learn.microsoft.com/en-us/dotnet/framework/network-programming/synchronous-server-socket-example
private static void ListenThread()
{
// Thread.CurrentThread.ManagedThreadId returns 3
// Opens socket and listens for command
if (/* command received */) {
OpenFormRequest?.Invoke();
}
}
}
The delegate callback function is run on the same thread as the socket listener. Not the UI thread as expected.
Can anyone explain what's happening please? I don't do a lot of .net development, so I am having trouble nutting this out.
As far as I can tell from the docs, the delegate should ensure that the callback is run on the UI thread. Can anyone suggest why it isn't?
There are no docs that should suggest that. I.e. it's not sufficient simply to use a delegate. You have to invoke the delegate using a mechanism that would move that invocation onto the UI thread, and there's nothing like that in the code you posted above. You seem to have misunderstood whatever it was that you read.
The issue with your code is that you appear to have confused the compiler-generated Invoke() method for a delegate with the framework-provided Control.Invoke() method. Your code calls the former, while you should be calling the latter. All that the former does is to actually invoke the delegate; the latter is what handles marshaling the execution of a delegate onto the UI thread so it can be executed there.
Frankly, it's a mistake for the socket-related code to try to address this at all. In the ListenThread() method, just raise the event normally (which ironically is the syntax you're using, so actually you don't need to change anything there). In your OpenFormCommandHandler() method, then you should call the Control.Invoke() method to execute whatever code you need to execute there, such as creating and showing a new form.
Based on your recent edit, in theory here is how you would change your event handler:
private void OpenFormCommandHandler()
{
// Thread.CurrentThread.ManagedThreadId returns 3
// Open the form
this.Invoke((MethodInvoker)(() => Visible = true;));
}
But I infer from your problem description that the form has not actually been shown once yet, which means it hasn't yet been tied to main thread and so Control.Invoke() is unlikely to work (you'd probably get an exception reporting that the window handle hadn't been created yet…I forget the exact wording, and it's not important enough for me to go looking it up right now).
Assuming that's the case, you need to get a synchronization context from elsewhere. Unfortunately, the question still lacks the specifics that would allow a more explicit answer showing exactly how to do that. But depending on what else is going on in your program, you could:
Pass a different Form instance to the wPrompt constructor and use that instance when calling Invoke(). Or,
Pass SynchronizationContext.Current to the wPrompt constructor, and call that object's Send() or Post() method (equivalent to Control.Invoke() and Control.BeginInvoke(), respectively).
There are other mechanisms you could use to capture and then use the synchronization context, but I'd say based on the details in your question, one of those two will be preferable to you.
I am working on understanding how to use BeginInvoke correctly. I wrote up a small test in a console app where all I am trying to do is use BeginInvoke to call a function to make a 100x100 Window with a title pop up. I am failing miserably. Here is what I have, I know this is probably just poor understanding of Threads (not my strong suit), but I'm stuck, no window pops up I just end up at my readline in Main waiting for a keypress. Execution starts at ThreadUITest.
static void ThreadUITest()
{
ThreadStart starter = new ThreadStart(threadFunc1);
Thread test = new Thread(starter);
test.IsBackground = true;
test.SetApartmentState(ApartmentState.STA);
test.Start();
}
static void threadFunc1()
{
dispatcher = Dispatcher.CurrentDispatcher; //Statically declared earlier
ThreadStart starter = new ThreadStart(threadFunc2);
Thread test = new Thread(starter);
test.IsBackground = true;
test.Start();
}
static void threadFunc2()
{
Action method = Draw;
Console.WriteLine("I'm here!");
//dispatcher.BeginInvoke( (Action)(() => {Draw();}),DispatcherPriority.Render, null);
dispatcher.BeginInvoke(method, DispatcherPriority.Send, null);
}
static void Draw()
{
Window win = new Window();
win.Height = 100;
win.Width = 100;
win.Title = "A Window!";
win.Show();
}
Thanks for any help.
You need to add the following at the bottom of your threadFunc1
// statically declared earlier, although you don't need to keep a reference to it as
// WPF will keep it in Application.Current
application = new Application();
application.Run(); // thread1 is now our "UI" thread
Why does this solve it?
The Dispatcher object provides an interface for getting a thread to do some work for you (via BeginInvoke or Invoke).
In order for a thread to be able to process any "do work" messages, it must be running some kind of event loop, where it sits and waits for the next message to process - if it weren't doing this, then it wouldn't be able to process anything, it would just be stuck.
Calling Dispatcher.CurrentDispatcher from thread1 will create a new dispatcher on that thread if there isn't one already there[1] - that gives us our interface to post messages to the thread.
What dispatcher.BeginInvoke does is add an entry into the message queue for that thread, however the thread isn't running any message loop yet. We can queue messages to it, but it won't pick them up and run them - this is why nothing happens.
So, we need to make that thread start running a message loop.
The Application.Run() method is the WPF framework method which does exactly that. The Application.Run method never returns (until you call Application.Shutdown anyway), it starts up a message loop to begin processing messages thereafter. I find it useful to think of it "taking over" the thread.
Now with this change, when thread2func calls dispatcher.BeginInvoke, the message loop code inside Application.Run goes "oh look, a message, I'll process it" - it gets the BeginInvoke method, and does what it's told (in this case, executing your Draw function), and all is well
Note: As per Ark-kun's answer You can also just call Dispatcher.Run to start a message loop on that thread without creating an Application object (Application.Run does this internally). Generally I find it nicer to create an application object though, as that's more "normal", and some other code you may write later on may expect an Application object to exist
[1] FYI, this is why calling Dispatcher.CurrentDispatcher is dangerous and you should avoid it. If you call Dispatcher.CurrentDispatcher from the existing UI thread, it returns you a reference to the correct dispatcher.
If you accidentally call it from another thread, logically, you'd think it would return a reference to the existing dispatcher. But no - instead, it creates a second dispatcher, pointing at our other thread - however our other thread won't be running a message loop, and we'll get stuck again. I'd suggest never calling Dispatcher.CurrentDispatcher except for the very first time.
Once your app is up and running, you generally don't need to do this anyway, as all WPF objects (Window, Button, etc) all have a Dispatcher property which you can use to get the correct dispatcher from anyway
Try calling Dispatcher.Run() in the end of threadFunc1.
Can anybody please explain this statement written on this link
Invoke(Delegate):
Executes the specified delegate on the thread that owns the control's underlying window handle.
Can anybody explain what this means (especially the bold one) I am not able to get it clearly
The answer to this question lies in how C# Controls work
Controls in Windows Forms are bound to a specific thread and are not
thread safe. Therefore, if you are calling a control's method from a
different thread, you must use one of the control's invoke methods to
marshal the call to the proper thread. This property can be used to
determine if you must call an invoke method, which can be useful if
you do not know what thread owns a control.
From Control.InvokeRequired
Effectively, what Invoke does is ensure that the code you are calling occurs on the thread that the control "lives on" effectively preventing cross threaded exceptions.
From a historical perspective, in .Net 1.1, this was actually allowed. What it meant is that you could try and execute code on the "GUI" thread from any background thread and this would mostly work. Sometimes it would just cause your app to exit because you were effectively interrupting the GUI thread while it was doing something else. This is the Cross Threaded Exception - imagine trying to update a TextBox while the GUI is painting something else.
Which action takes priority?
Is it even possible for both to happen at once?
What happens to all of the other commands the GUI needs to run?
Effectively, you are interrupting a queue, which can have lots of unforeseen consequences. Invoke is effectively the "polite" way of getting what you want to do into that queue, and this rule was enforced from .Net 2.0 onward via a thrown InvalidOperationException.
To understand what is actually going on behind the scenes, and what is meant by "GUI Thread", it's useful to understand what a Message Pump or Message Loop is.
This is actually already answered in the question "What is a Message Pump" and is recommended reading for understanding the actual mechanism that you are tying into when interacting with controls.
Other reading you may find useful includes:
What's up with Begin Invoke
One of the cardinal rules of Windows GUI programming is that only the
thread that created a control can access and/or modify its contents
(except for a few documented exceptions). Try doing it from any other
thread and you'll get unpredictable behavior ranging from deadlock, to
exceptions to a half updated UI. The right way then to update a
control from another thread is to post an appropriate message to the
application message queue. When the message pump gets around to
executing that message, the control will get updated, on the same
thread that created it (remember, the message pump runs on the main
thread).
and, for a more code heavy overview with a representative sample:
Invalid Cross-thread Operations
// the canonical form (C# consumer)
public delegate void ControlStringConsumer(Control control, string text); // defines a delegate type
public void SetText(Control control, string text) {
if (control.InvokeRequired) {
control.Invoke(new ControlStringConsumer(SetText), new object[]{control, text}); // invoking itself
} else {
control.Text=text; // the "functional part", executing only on the main thread
}
}
Once you have an appreciation for InvokeRequired, you may wish to consider using an extension method for wrapping these calls up. This is ably covered in the Stack Overflow question Cleaning Up Code Littered with Invoke Required.
There is also a further write up of what happened historically that may be of interest.
A control or window object in Windows Forms is just a wrapper around a Win32 window identified by a handle (sometimes called HWND). Most things you do with the control will eventually result in a Win32 API call that uses this handle. The handle is owned by the thread that created it (typically the main thread), and shouldn't be manipulated by another thread. If for some reason you need to do something with the control from another thread, you can use Invoke to ask the main thread to do it on your behalf.
For instance, if you want to change the text of a label from a worker thread, you can do something like this:
theLabel.Invoke(new Action(() => theLabel.Text = "hello world from worker thread!"));
If you want to modify a control it must be done in the thread in which the control was created. This Invoke method allows you to execute methods in the associated thread (the thread that owns the control's underlying window handle).
In below sample thread1 throws an exception because SetText1 is trying to modify textBox1.Text from another thread. But in thread2, Action in SetText2 is executed in the thread in which the TextBox was created
private void btn_Click(object sender, EvenetArgs e)
{
var thread1 = new Thread(SetText1);
var thread2 = new Thread(SetText2);
thread1.Start();
thread2.Start();
}
private void SetText1()
{
textBox1.Text = "Test";
}
private void SetText2()
{
textBox1.Invoke(new Action(() => textBox1.Text = "Test"));
}
Invoke((MethodInvoker)delegate{ textBox1.Text = "Test"; });
In practical terms it means that the delegate is guaranteed to be invoked on the main thread. This is important because in the case of windows controls if you don't update their properties on the main thread then you either don't see the change, or the control raises an exception.
The pattern is:
void OnEvent(object sender, EventArgs e)
{
if (this.InvokeRequired)
{
this.Invoke(() => this.OnEvent(sender, e);
return;
}
// do stuff (now you know you are on the main thread)
}
this.Invoke(delegate) make sure that you are calling the delegate the argument to this.Invoke() on main thread/created thread.
I can say a Thumb rule don't access your form controls except from main thread.
May be the following lines make sense for using Invoke()
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;
}
}
There are situations though you create a Threadpool thread(i.e worker thread) it will run on main thread. It won't create a new thread coz main thread is available for processing further instructions. So First investigate whether the current running thread is main thread using this.InvokeRequired if returns true the current code is running on worker thread so call
this.Invoke(d, new object[] { text });
else directly update the UI control(Here you are guaranteed that you are running the code on main thread.)
It means that the delegate will run on the UI thread, even if you call that method from a background worker or thread-pool thread. UI elements have thread affinity - they only like talking directly to one thread: the UI thread. The UI thread is defined as the thread that created the control instance, and is therefore associated with the window handle. But all of that is an implementation detail.
The key point is: you would call this method from a worker thread so that you can access the UI (to change the value in a label, etc) - since you are not allowed to do that from any other thread than the UI thread.
Delegate are essentially inline Action's or Func<T>. You can declare a delegate outside the scope of a method which you are running or using a lambda expression(=>); because you run the delegate within a method, you run it on the thread which is being run for the current window/application which is the bit in bold.
Lambda example
int AddFiveToNumber(int number)
{
var d = (int i => i + 5);
d.Invoke(number);
}
It means that the delegate you pass is executed on the thread that created the Control object (which is the UI thread).
You need to call this method when your application is multi-threaded and you want do some UI operation from a thread other than the UI thread, because if you just try to call a method on a Control from a different thread you'll get a System.InvalidOperationException.
While maintaining some code, I discovered that we have an infinite hang-up in a background worker. The worker requires access to a script file. The original code was written to pop up a file dialog if no script file was defined, to allow the user to select one. It looks something like this:
private void bgworker_DoWork(object sender, DoWorkEventArgs e)
{
... snip ...
if (String.IsNullOrWhitespace(scriptFile))
{
scriptFile = PromptForScript();
}
... snip ...
}
private string PrompForScript()
{
string script = "";
OpenFileDialog openDialog = new OpenFileDialog();
if (openDialog.ShowDialog() == DialogResult.OK)
{
script = openDialog.FileName;
}
return script;
}
I've read up a bit about MethodInvoker, but almost all of the invoke methods require that you call them from a control. The background worker in question is running from a separate class, which doesn't extend Control. Do I use the form that calls the class with the bgworker for that? Or is there another way of interrupting the thread for user input?
It's not recommended to invoke the UI from the background worker DoWork event handler. BackgroundWorker is meant to do work on a non-UI thread to keep the UI responsive. You should ask for any file information before starting the BackgroundWorker object with RunWorkerAsync.
What you want to do is capture the SynchronizationContext on the UI thread and pass that along to the background worker. The BackgroundWorker can call Send() (synchronous, like Invoke) and Post() (asynchronous, like BeginInvoke) on the context to invoke back to the correct UI thread. That said, there is probably no need for the BackgroundWorker in this case- a regular threadpool thread would do just fine.
This (slightly modified) block of code from http://msmvps.com/blogs/manoj/archive/2005/11/03/74120.aspx should give you the general idea:
private void button1_Click(object sender, EventArgs e)
{
// Here we are on the UI thread, so SynchronizationContext.Current
// is going to be a WindowsFormsSynchronizationContext that Invokes properly
ctx = SynchronizationContext.Current;
ThreadPool.QueueUserWorkItem(
// This delegate is going to be invoked on a background thread
s => {
// This uses the context captured above to invoke
// back to the UI without the "messy" referencing
// of a particular form
ctx.Send(s2 =>
{
// Interact with your UI here- you are on the UI thread
},null);
}
);
}
If some Form kicks off a long-running process within another class that uses a BGworker, why wouldn't the form (or presenter, depending on UI architecture) handle the processing of the error state?
Perhaps, just pass back some status result (or throw a very targeted, specific exception that you can handle in the UI)?
Leave the background worker to determine if there IS an error, but leave handing the error (especially the UI portion of showing a message box) to the upper layers.
Sorry this didn't have more concrete code but it could go a lot of different ways depending on how your system is architected.
Well, the Form class has an Invoke method, so passing the form instance to the background working class should work.
I am just working on my first GUI application on Windows.
I have a WPF GUI to a small C# utility which copies files. When the button is clicked to copy, I obviously don't want the GUI to hang. So, I fire off a new thread to run the method which copies the files. I assume I'm on track so far and there's no "better" way of doing it in C#?
Now, I have a ProgressBar which I want to appear filled when the thread is done. (It's fine running as indeterminate for now). How do I check when the copying is done?
So, so far I have:
Thread t = new Thread(delegate()
{
po.Organise(inputPath, outputPath, recursive);
});
t.Start();
PBar.IsIndeterminate = true;
And I want something after that that works like:
if (t.Done)
{
PBar.Value = 100;
}
Have a look at the BackgroundWorker class. It supports events like RunWorkerCompleted or ProgressChanged.
Have a look here, too (this is about threading in general + backgroundworker, again).
As already stated, consider the use of the BackgroundWorker class. It was designed for these situations and exposes events suited for what you are trying to accomplish.
Use the ProgressChangedevent to report progress incrementally and the RunWorkerCompleted for when the task finishes. Check the MSDN page for code samples.
Wrap the if (t.Done) block in its own method. Invoke this method from the end of your worker thread.
Also, you might want to give the worker thread a name to make it easier to spot in the debugger.
You need a callback method. This should get you started. It uses an AsyncCallback, which is the best way to tackle this type of issue.
I just looked up an example I've been using for a project and stripped out the code specific to my app:
System.Windows.Forms.MethodInvoker mi = new System.Windows.Forms.MethodInvoker(delegate()
{
// Do your file copy here
});
AsyncCallback ascb = new AsyncCallback(delegate(IAsyncResult ar)
{
this.Dispatcher.Invoke(new ThreadStart(delegate (){
// set progressbar value to 100 here
}), null);
});
mi.BeginInvoke(ascb, null);
The quick and easy hack would be to just update the UI at the end of your anonymous method in your thread. Obviously you can't update it directly, but you can use Dispatcher.Invoke:
Thread t = new Thread(delegate()
{
po.Organise(inputPath, outputPath, recursive);
Dispatcher.Invoke(new Action(()=>{PBar.Value = 100;}),null);
});
t.Start();
As a general Windows programming principal, you have to make calls to update the UI from the UI thread (the one that is processing messages through a message pump).
In Windows Forms, the way that this was done was through the implementation of the ISynchronizeInvoke interface on the Control class, primarily through the implementation of the Invoke method.
With the release of .NET 2.0, it was realized that a better mechanism was needed to marshal calls into the correct context. That's where the SynchronizationContext comes in.
This class abstracts the interface you would use for marshaling calls to different contexts, allowing for specific implementations depending on the context.
So whether or not Windows Forms is the environment, or WPF, one call can be made in the same way across those contexts with the same effect (marshaling the call).
In your particular case, because you are using a closure (anonymous method), you can take advantage of the fact that a SynchronizationContext is available to you (through the static Current property) at the invocation site of the Thread to provide the mechanism to call back to the UI thread from your background thread:
// Get the synchronization context.
// This is in the UI thread.
SynchronizationContext sc = SynchronizationContext.Current;
// Create the thread, but use the SynchronizationContext
// in the closure to marshal the call back.
Thread t = new Thread(delegate()
{
// Do your work.
po.Organise(inputPath, outputPath, recursive);
// Call back using the SynchronizationContext.
// Can call the Post method if you don't care
// about waiting for the result.
sc.Send(delegate()
{
// Fill the progress bar.
PBar.Value = 100;
});
});
// Make the progress bar indeterminate.
PBar.IsIndeterminate = true;
// Start the thread.
t.Start();
Note, if you don't care about waiting for the result of the call back to the UI thread, you can make a call to the Post method instead, which will dispatch the call to the UI thread without waiting for that call to complete.