Using C# MethodInvoker.Invoke() for a GUI app... is this good? - c#

Using C# 2.0 and the MethodInvoker delegate, I have a GUI application receiving some event from either the GUI thread or from a worker thread.
I use the following pattern for handling the event in the form:
private void SomeEventHandler(object sender, EventArgs e)
{
MethodInvoker method = delegate
{
uiSomeTextBox.Text = "some text";
};
if (InvokeRequired)
BeginInvoke(method);
else
method.Invoke();
}
By using this pattern I do not duplicate the actual UI code but what I'm not sure about is if this method is good.
In particular, the line
method.Invoke()
does it use another thread for invoking or does it translate somewhat to a direct call to the method on the GUI thread?

The method.Invoke() call executes the delegate on the current executing thread. Using the BeginInvoke(method) ensures that the delegate is called on the GUI thread.
This is the correct way of avoiding code duplication when the same method can be called both from the GUI thread and other threads.

Personally I like this method:
private void ExecuteSecure(Action a)
{
if (InvokeRequired)
BeginInvoke(a);
else
a();
}
And then you can write one-liners like this:
ExecuteSecure(() => this.Enabled = true);

Keep in mind that Control.InvokeRequired returns false if you are on background thread AND Control.IsHandleCreated is false. I would safeguard the code with a Debug.Assert that checks for unmanaged handle creation.

For WinForms, calling Control.Invoke(Delegate) sends a message to the UI's thead's message pump. The thread then processes the message and calls the delegate. Once it has been processed, Invoke stops blocking and the calling thread resumes running your code.

It makes the call on the same thread. You can check by stepping through the code. There is nothing wrong with that approach.

Related

Creating new BackgroundWorker for every async task

I create a new BackgroundWorker every time I need to do any Async task and after the work is done I Dispose it but I've a doubt if that completely disposes it because the Dispose method is implemented by System.ComponentModel.Component
In a typical run of the program, thousands of them may be created. Is it okay if millions of them (to be on the safe side) get created or should I do it some other way?
Most of the async work is I/O and I can't use async/await because I'm using .NET 4 (can't use 4.5).
I've wrapped the whole thing in this method:
public void AsyncDo(Action Action, Action ActionFinish = null)
{
using (BackgroundWorker bw = new BackgroundWorker()) {
bw.DoWork += () => Action();
bw.RunWorkerCompleted += (s, e) =>
{
if (ActionFinish != null)
ActionFinish();
if (e.Error != null)
OnException(e.Error);
};
bw.RunWorkerAsync();
}
}
Based on the answers, I've updated it with
Task t = new Task(action);
t.Start();
But I get a cross-thread error when I do actionFinish() by combining it with action or calling t.ContinueWith(). This wasn't the case in the BGW, it didn't require invoking for RunWorkerCompleted. I can't change every call to this method to make them use invoking, what should I do?
BackgroundWorker is specifically designed to allow code to run in the background with respect to the UI thread, while also allowing simple synchronization with the UI.
If you need to do any async task, just use Task - that's what it's designed for. If you don't have .NET 4+, you'll need to use Thread (or better, ThreadPool.QueueUserWorkItem) instead - but that's even more complex (while looking deceptively simple). As always, http://www.albahari.com/threading/ should be your starting point when trying to implement multi-threading (or asynchronous code in general) :)
EDIT:
To get a behaviour close to what you had originally with BackgroundWorker, you can simply add a continuation to run on the UI thread:
var task = Task.Factory.StartNew(yourAction);
task.ContinueWith(yourResultAction, TaskScheduler.FromCurrentSynchronizationContext());
All of this is strongly typed, so it's quite easy to pass an arbitrary value from the yourAction task (running on a worker thread) to the yourResultAction task (running on the UI thread). Note that the TaskScheduler.FromCurrentSynchronizationContext() must be run on the UI thread, of course.
You can wrap this in a simple helper function that will just take the two actions, and return a task (either the original task, or the continuation task - that depends on what you want to do with it).
Also, Microsoft.Bcl.Async brings most of .NET 4.5+'s await goodness to .NET 4.0 - after all, await is all in the compiler, it doesn't need a new runtime to work. Working with await is much simpler than working with continuations, especially when doing error handling.
A race condition occurs when two or more threads access shared data, for writing, at the
same time. (How to deal with race conditions is covered later in this chapter in the “Synchronizing
Resources” section.) If you try to update the UI from another thread, .NET Framework throws an
InvalidOperationException containing the following message: "Cross-thread operation not
valid: Control 'ctrlName' accessed from a thread other than the thread it was
created on."
To solve the problem, change the worker_RunWorkerCompleted method
as follows:
void _worker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) {
if (this.InvokeRequired) {
this.Invoke(
new Action(ActionFinish));
}
else {
ActionFinish();
}
}
In the worker_RunWorkerCompleted method, you now check the InvokeRequired
property. This property is defined in the Control class, and as such is present on all the controls on a page. InvokeRequired is set to false if you call it from the UI thread and true
otherwise.
The Invoke method takes as the first parameter a delegate, meaning any method can be
placed there. The new Action() constructor call is used to make sure that you
get a delegate. If your method has a different signature, you must change that constructor
accordingly. The rest of the parameters of the Invoke method are sent directly to the method
you want to run. Invoke places the method call in a queue to be picked up by the UI thread.
A better solution ?
void worker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e { this.Dispatcher.Invoke(()=> //statement); }
It is enough to call the Dispatcher.Invoke method in all the situations. This call
ensures that the lambda expression ()=> //statement is run by the UI thread,
regardless from which thread the method is called.
A BackgroundWorker and a task are both windows processes so I don't know why you need both. A class is also a process, but I like using a separate class rather than a task.
Imports System.ComponentModel
Module Module1
Sub Main()
Dim backgroundWorker As New MyBackGroundWorker
backgroundWorker.Dispose()
End Sub
End Module
Class MyBackGroundWorker : Implements IDisposable
Dim backgroundWorker As New BackgroundWorker
Sub Dispose() Implements IDisposable.Dispose
Me.Dispose()
End Sub
End Class

Invoke(Delegate)

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.

How to post a UI message from a worker thread in C#

I'm writing a simple winforms app in C#. I create a worker thread and I want the main window to respond to the tread finishing its work--just change some text in a text field, testField.Text = "Ready". I tried events and callbacks, but they all execute in the context of the calling thread and you can't do UI from a worker thread.
I know how to do it in C/C++: call PostMessage from the worker thread. I assume I could just call Windows API from C#, but isn't there a more .NET specific solution?
In the event callback from the completed thread, use the InvokeRequired pattern, as demonstrated by the various answers to this SO post demonstrate.
C#: Automating the InvokeRequired code pattern
Another option would be to use the BackgroundWorker component to run your thread. The RunWorkerCompleted event handler executes in the context of the thread that started the worker.
i normally do something like this
void eh(Object sender,
EventArgs e)
{
if (this.InvokeRequired)
{
this.Invoke(new EventHandler(this.eh, new object[] { sender,e });
return;
}
//do normal updates
}
The Control.Invoke() or Form.Invoke() method executes the delegate you provide on the UI thread.
You can use the Invoke function of the form. The function will be run on the UI thread.
EX :
...
MethodInvoker meth = new MethodInvoker(FunctionA);
form.Invoke(meth);
....
void FunctionA()
{
testField.Text = "Ready".
}
Using C# MethodInvoker.Invoke() for a GUI app... is this good?

Performance implications of BeginInvoke

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.

C# How does a background thread tell a UI thread that it has finished doing something?

Scenario
Lets say you have a C# WinForms application that doing some data processing.
You have a method that retrieves data from a database that is called by the UI thread.
The background thread then runs off to do this task.
You want the UI to carry on doing its thing and not be locked up and unresponsive.
QUESTION
How do you let the background thread run off and do its processing and then automatically alert the UI thread when it has returned the results?
If you don't use a background worker thread (for whatever reason) then you must fire an event from your thread which is handled by the UI thread. For example I have this code that scans my mp3s and fires and event for each album found and then another event when it finished (or is stopped):
public void Build()
{
FindAlbums(Root);
// Final update
if (Library_Finished != null)
{
Library_Finished(this, null);
}
}
private void FindAlbums(string root)
{
// Find all the albums
string[] folders = Directory.GetDirectories(root);
foreach (string folder in folders)
{
string[] files = Directory.GetFiles(folder, "*.mp3");
if (files.Length > 0)
{
// Add to library - use first file as being representative of the whole album
var info = new AlbumInfo(files[0]);
if (Library_AlbumAdded != null)
{
Library_AlbumAdded(this, new AlbumInfoEventArgs(info));
}
}
FindAlbums(folder);
}
}
Then in the UI thread (this is WinForms code):
private void Library_AlbumAdded(object sender, AlbumInfoEventArgs e)
{
if (dataGridView.InvokeRequired)
{
dataGridView.Invoke((MethodInvoker)delegate { AddToGrid(e.AlbumInfo); });
}
else
{
AddToGrid(e.AlbumInfo);
}
}
private void Library_Finished(object sender, EventArgs e)
{
if (dataGridView.InvokeRequired)
{
dataGridView.Invoke((MethodInvoker)delegate { FinalUpdate(); });
}
else
{
FinalUpdate();
}
}
I would, however, recommend that you investigate the background worker thread, as it does so much of the housekeeping for you. However, the same handling code would be needed in the RunWorkerCompleted event to update the UI.
There are several ways of doing this, but the easiest way is to use a BackgroundWorker.
Essentially it has two delegates, the DoWork and the WorkCompleted. DoWork executes on a seperate thread and the WorkCompleted callback happens on the UI thread.
Here's more info:
http://msdn.microsoft.com/en-us/library/system.componentmodel.backgroundworker.aspx
You can use the BackgroundWorker to do your time-intensive processing in its DoWork event handler. Then handle the RunWorkerComplete event -- it will fire when the DoWork method is finished. While all this is going on, your UI thread will be happily running along.
If you're using .NET 2.0 or newer, then this is made much easier with the BackgroundWorker thread. It has its own RunWorkerCompleted event that does just what you need.
I would highly recommend the BackgroundWorker in fact. It has the functionality most developers are after when creating threads. They're also easier to cancel gracefully, and they even have the ability to report progress.
Try to use BackgrounWorker and register a handler to the its RunWorkerCompleted event.
In Winforms you can use the .Invoke method (and check the .InvokeRequired property) to marshall a call back to the UI thread. You don't so much notify the UI thread - it keeps going on and doesn't wait for any sort of a completion, but you can interact with a control (for example, update the text property of a label) from another thread using the Invoke method.
You can also use the BackgroundWorker object (read MSDN to find out more about it), which implements a callback functionality to run some code on the UI thread after the background work is completed.
If you are talking about a WinForm app, you can make changes to any UI objects using the Invoke method on your form (or any of the controls on the form). You can also find useful the InvokeRequired property
You can store a reference to the UI thread Dispatcher by using Dispatcher.CurrentDispatcher (obviously in a method called by GUI thread). Using this object you can use the BeginInvoke or Invoke methods in your working thread to execute a method on the GUI thread notifying it that you have completed work. Personally I find this method to be slightly more flexible than using a background worker object and can produce slightly more readable code.
There's an easy way of working with multiple threads in C#. It is called BackgroundWorker.
You should check it out: BackgroundWorker Tutorial
As was mentioned many times, the BackgroundWorker class can be used.
Alternatively, you could do something akin to the following:
void buttonGo_Clicked( object sender, EventArgs e )
{
MyAsyncClass class = new MyAsyncClass();
class.LongOperationFinished += (LongOperationFinishedEventHandler)finished;
class.BeginLongOperation();
}
void finished( object sender, EventArgs e )
{
if( this.InvokeRequired ) {
this.BeginInvoke( (LongOperationFinishedEventHandler)finished, sender, e );
return;
}
// You can safely modify the gui here.
}

Categories