Background Worker events - c#

pseudo code:
form1
{
int i;
label1;
Add()
{
i++;
label1 = i.ToString(); //#ErrorLine
}
backgroundworker worker;
worker_DoWork()
{
FileGuard guard = new FileGuard();
guard.FileKilled += guard.KillH(Add);
guard.StarGuarding(); //there is system watcher inside
//this guard and some processing code
//that will fire event FileKilled();
}
}
Afer calling StartGuarding() worker will be compleated
But when there is event FileKilled fired I goth this error on line #ErrorLine
Cross-thread operation not valid: Control 'form1' accessed from a thread other than the thread it was created on.

This has nothing to do with the events themselves, but rather the fact that you are accessing UI controls from another thread. In Windows Forms, you are not allowed to interact with the UI from any other thread than the main UI thread.
You can use InvokeRequired to check whether you are on a thread that has no access to the UI, and then use Invoke to run code on the UI thread if required. It might look something like this:
private void DoStuffWithGUI()
{
if (InvokeRequired)
{
Action work = DoStuffWithGUI;
Invoke(work);
}
else
{
// Your normal logic
}
}
You can use the UI directly from ProgressChanged and RunWorkerCompletedEvents (because they are automatically marshalled to the UI thread). But all work you do within DoWork, (and therefore all events you might raise as part of the work) runs in a separate thread, and must be marshalled to the UI thread using Invoke. From MSDN for BackgroundWorker:
You must be careful not to manipulate
any user-interface objects in your
DoWork event handler. Instead,
communicate to the user interface
through the ProgressChanged and
RunWorkerCompleted events.

It's because a third thread is used when FileKilled is invoked by the system.
As for BackgroundWorker you should use events to handle GUI updates: http://msdn.microsoft.com/en-us/library/system.componentmodel.backgroundworker.aspx

You cannot access Windows Forms or WPF objects from anything other than the form they were created on, hence your issue.
Use a dispatcher to send the update back to your UI Thread.
If you can give detail on whether you're using WinForms or WPF we can give more information.

You cannot change modify the controls from a thread other than on which they were created. You need to use the InvokeRequired property and Invoke method to marshal the calls to the UI thread from the background thread.
private readonly _lockObject = new Object();
Add()
{
lock(_lockObject)
{
i++;
if(label1.InvokeRequired)
Invoke(new Action( () => label1 = i.ToString()));
else
label1 = i.ToString();
}
}
Note that the lock is not necessary to avoid this exception. It added to make the method thread safe.

Related

When is a UI Element assigned to thread

I know I have seen an article or SO on this before, but cannot seem to find it now. I ran into a problem helping a coworker write a test that was checking UI actions that were occurring across multiple threads (I realize the problems here...that is not what I want to focus on at the moment :)). The code looks similar to this kind of pseudocode:
[RequiresSTA]
Test
{
var tb = new Textbox();
tb.DoSomethingAsyncAndThenUpdateTB() //This is done via tb.SetValue being called
}
...
DoSomethingAsyncAndThenUpdateTB()
{
var bw = new BackgroundWorker();
bw.DoWork += ...Do Stuff...
bw.RunWorkerCompleted += { tb.Text = "foo";}
}
The problem I am running into is that the OnComplete is throwing a cross thread exception. However, everything should have been created on the STA thread. I BELIEVE the problem is that UI elements get attached to their thread not on creation, but at a later point....and my textbox ends up attaching to a thread that isn't the STA? Or maybe the backgroundworker?
The question:
When does a UI element actually get attached to a thread?
So first off, there isn't just one STA thread. Any thread can be created as an STA thread when it's created. The UI thread needs to be an STA thread, but not all STA threads are UI threads.
Next, you have the issue that BackgroundWorker needs to have some way of knowing what the UI thread is. It's not magic that it's able to marshal certain events to the UI thread. What it does is it looks at the value of SynchronizationContext.Current in its constructor. It then captures the value of that context, and uses it later as it's definition of the context to post all non-work events to. If you create the BGW outside of the UI thread then it's not able to marshal back to the UI thread later.
If you have an STA thread that you are using as your UI thread, but you haven't set a value of SynchronizationContext.Current, then the BGW won't be able to do its thing.
As for the question of:
When does a UI element actually get attached to a thread?
In its constructor.
Each ui element implements DependencyObject, which implements abstract class DispatcherObject.. When DispatcherObject is created it assigns current dispatcher to the DispatcherObject..
Later on, whenever you access any property of the UI element, there is a validation that checks if you are accessing it from UI thread.
This si done in VerifyAccess
/// <summary>Enforces that the calling thread has access to this <see cref="T:System.Windows.Threading.DispatcherObject" />.</summary>
/// <exception cref="T:System.InvalidOperationException">the calling thread does not have access to this <see cref="T:System.Windows.Threading.DispatcherObject" />.</exception>
[EditorBrowsable(EditorBrowsableState.Never)]
public void VerifyAccess()
{
Dispatcher dispatcher = this._dispatcher;
if (dispatcher != null)
{
dispatcher.VerifyAccess();
}
}
If a calling thread is not the one associated with dispatcher, then exception is thrown
public void VerifyAccess()
{
if (!this.CheckAccess())
{
throw new InvalidOperationException(SR.Get("VerifyAccess"));
}
}
This is called Thread Affinity

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.

Fire events from different thread

In my main window (Thread A), I start a new thread (Thread B) which does some work while the user waits.
Thread B fires events if there is an error or extra information is required from the user, Thread A will listen to these events.
In Thread A's event listener I need to show dialog messages to the user, I have a custom dialog window and show it using dialogWindow.showDialog(). This works fine, but causes an error when I try and set the owner of the dialog, I do this dialogWindow.Owner = Window.GetWindow(this).
The error that I get is: The calling thread cannot access this object because a different thread owns it.
What is the correct way to listen for events that are fired from a different thread?
The event listener code will run implicitly at the thread which fires the event, so the event listener is not thread-bound.
If you want to show something in the UI as a result of event handling, you should do the marshalling yourself. Something like that:
void OnEvent(object sender, EventArgs args)
{
// runs in the event sender's thread
string x = ComputeChanges(args);
Dispatcher.BeginInvoke((Action)(
() => UpdateUI(x)
));
}
void UpdateUI(string x)
{
// runs in the UI thread
control.Content = x;
// - or -
new DialogWindow() { Content = x, Owner = this }.ShowDialog();
// - or whatever
}
So: you execute your computations (if any) preferrably in the background thread, without touching the UI; after that, when you know which are the needed changes in the UI, you execute the UI-updating code in the UI thread.
The Dispatcher is a property of a control, so if your code is a part of UI, you'll have your Dispatcher for free. Otherwise, you can take the dispatcher from any of the controls (e.g., control.Dispatcher).
The correct way to raise an event to the UI thread from the background thread is that, the event should be raised on that Dispatcher,
Key here is get the dispatcher of UIthread before hand.
UIDisaptcher.BeginInvoke((ThreadStart)(() => RaiseEventToUIThread()));
when the UI thread listens to the raised event it can set the Owner property(as the window was created by the UI thread).
Sure -> what we do is to use the SynchronizationContext.
So when you start a new thread, you capture (on UI thread) the current context and pass it into the second thread as parameter.
Then on the second thread when you want to raise an event you do it this way:
if (_uiThreadId != Thread.CurrentThread.ManagedThreadId)
{
_uiContext.Post(
new SendOrPostCallback(delegate(object o) { OnYourEvent((EventArgs)o); }),
e);
}
else
OnYourEvent(e);

Why can't UI components be accessed from a backgroundworker?

Threads all share resources. That's the whole problem around multi-threaded operations.
MSDN says:
You must be careful not to manipulate any user-interface objects in your DoWork event >handler. Instead, communicate to the user interface through the ProgressChanged and RunWorkerCompleted events.
BackgroundWorker events are not marshaled across AppDomain boundaries. Do not use a BackgroundWorker component to perform multithreaded operations in more than one AppDomain.
And yet when I use the backgroundworker, it's not that I need to be careful not to manipulate any UI objects, it's that can't_ if I try to access the UI components from the DOWork event. The code compiles, but when the code for the DoWork runs, I get an error:
Cross-thread operation not valid: Control 'utAlerts' accessed from a thread other than the thread it was created on.
MSDN doesn't say anything about how is this done or why. Is the backgroundworker decorated with some attribute that prevents this? How is this accomplished?
If you're handler is an instance method in your UI class, you should have access to the members of that class.
it's that my app won't even compile if I try to access the UI components from the DOWork event.
This will only happen if your DoWork handler is static or in a different class than the UI components. In that case, you may not have access to them, as they are not visible to you.
Edit:
BackgroundWorker is intended to do "work" that is unrelated to your User Interface. You cannot change User Interface elements on any thread other than the UI thread, as user interface elements tend to have thread affinity. This actually has nothing to do with BackgroundWorker, but rather threading and user interface elements.
BW is intended to work around this by giving you progress and completion events that are automatically marshalled back onto the UI thread for you, allowing you to change UI elements there. However, you can always do this directly yourself via Control.Invoke in Windows Forms or Dispatcher.Invoke in WPF.
As to how this works - It depends on what framework you're using. For example, in Windows Forms, every Control (which is the base class of all of the UI elements) has a Handle, and the Handle is internally a native window handle. This handle is used to check the window's Thread ID against the current thread ID. This allows the check to be made without storing extra variables.
The error that you get when you try to change/update UI controls with a BackgroundWorker has nothing to do with sharing resources over the thread. It simply states that you cannot alter a control that was created on another thread.
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
textBox1.Text = "Test";
}
Results in:
Cross-thread operation not valid: Control accessed from a thread other than the thread it was created on.
This is used so that multiple threads are not accessing/changing the same controls at the same time. BackgroundWorkers are Asynchronous and could cause a lot of problems if controls were updated while the main thread updating them as well.
I do not know how they achieved this, however, it is probably in the best interest that they prevented this from happening.
The MSDN provided another line of documentation to the segment you copied which states "BackgroundWorker events are not marshaled across AppDomain boundaries. Do not use a BackgroundWorker component to perform multithreaded operations in more than one AppDomain."
EDIT CORRESPONDES TO CONVERSATION IN COMMENTS:
private void Form1_Load(object sender, EventArgs e)
{
TextBox.CheckForIllegalCrossThreadCalls = false;
backgroundWorker1.RunWorkerAsync();
}
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
textBox1.Text = "Test";
}
With the addition of the CheckForIllegalCrossThreadCalls = false, this code executes without error.
In the summary of the boolean property, it states that it indicates whether to "catch calls on the wrong thread."
It can be done with something as simple as having each control store the current thread (or maybe just its ID) in a private field in the constructor and then checking if the current thread is still that one before every method. Something like this:
class ThreadAffineObject
{
private readonly Thread originalThread;
public ThreadAffineObject()
{
this.originalThread = Thread.CurrentThread;
}
private void PreventCrossThreadOperation()
{
if(Thread.CurrentThread != originalThread)
throw new CrossThreadOperationException();
}
public void DoStuff()
{
PreventCrossThreadOperation();
// Actually do stuff
}
private int someField;
public int SomeProperty
{
get { return someField; } // here reading is allowed from other threads
set
{
PreventCrossThreadOperation(); // but writing isn't
someField = value;
}
}
}

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