Update UI from multiple worker threads (.NET) - c#

I have a pet project that I'm working on that has multiple worker threads. Outputting everything to the console is getting hard to follow, so I want to develop a UI that will have one output area per thread. I want to know the best way for the threads to send updates to the UI. I have two ideas:
1) Have each thread set a "DataUpdated" flag when new data is available, and have the UI periodically check for new data.
2) Create each thread with a callback to a UI Update(...) method to be called when new data becomes available.
I am currently leaning toward (2) for two reasons: I dislike the idea of "checking" each thread, and because this is my first multithreaded application and (2) seems simpler than it probably is. I want to know:
Which option is preferable in terms of simplicity and efficiency?
Do you have any tips for implementing (2) or something like it (i.e. more event-driven)?

You can easily implement (2) by creating BackgroundWorker components and doing the work in their DoWork handlers:
BackgroundWorker bw = new BackgroundWorker();
bw.WorkerReportsProgress = true;
bw.DoWork += /* your background work here */;
bw.ProgressChanged += /* your UI update method here */;
bw.RunWorkerAsync();
Each BackgroundWorker can report progress to the UI thread by calling ReportProgress: although this is primarily designed for reporting progress on a bounded process, that's not mandatory -- you can pass your own custom data as well if that's what your UI update requires. You would call ReportProgress from your DoWork handler.
The nice thing about BackgroundWorker is that it takes care of a lot of messy cross-threading details for you. It also conforms to the event-driven model of updates which you (rightly) prefer to explicit callbacks.

In most cases the easiest thing to do would be to use the BackgroundWorker component as suggested in itowlson's answer, and I would strongly suggest using that approach if possible. If, for some reason, you can't use a BackgroundWorker component for your purpose, such as if you're developing with .Net 1.1 (yikes!) or with compact framework, then you might need to use an alternative approach:
With Winform controls you have to avoid modifying controls on any thread other than the thread that originally created the control. The BackgroundWorker component handles this for you, but if you aren't using that, then you can and should use the InvokeRequired property and Invoke method found on the System.Windows.Forms.Control class. Below is an example that uses this property and method:
public partial class MultithreadingForm : Form
{
public MultithreadingForm()
{
InitializeComponent();
}
// a simple button event handler that starts a worker thread
private void btnDoWork_Click(object sender, EventArgs e)
{
Thread t = new Thread(WorkerMethod);
t.Start();
}
private void ReportProgress(string message)
{
// check whether or not the current thread is the main UI thread
// if not, InvokeRequired will be true
if (this.InvokeRequired)
{
// create a delegate pointing back to this same function
// the Invoke method will cause the delegate to be invoked on the main UI thread
this.Invoke(new Action<string>(ReportProgress), message);
}
else
{
// txtOutput is a UI control, therefore it must be updated by the main UI thread
if (string.IsNullOrEmpty(this.txtOutput.Text))
this.txtOutput.Text = message;
else
this.txtOutput.Text += "\r\n" + message;
}
}
// a generic method that does work and reports progress
private void WorkerMethod()
{
// step 1
// ...
ReportProgress("Step 1 completed");
// step 2
// ...
ReportProgress("Step 2 completed");
// step 3
// ...
ReportProgress("Step 3 completed");
}
}

I vote for #2 as well but with BackgroundWorkers instead of System.Threading.Threads.

You can have your worker threads raise events and have the main UI thread add event handlers. You need to be careful you're not raising too many events as it could get ugly if your worker threads are raising multiple events per second.
This article gives a quick overview.

The preferred way to implement multithreading in your application is to use the BackgroundWorker component. The BackgroundWorker component uses an event-driven model for multithreading. The worker thread runs your DoWork event handler, and the thread that creates your controls runs your ProgressChanged and RunWorkerCompleted event handlers.
When you update your UI controls in the ProgressChanged eventhandler, they are automatically updated on main thread which will prevent you from getting crossthread exceptions.
Look here for an example on how to use the backgroundworker.

If you're creating your own threads (non BackgroundWorker or ThreadPool threads) you can pass a callback method from your main thread that's called from the worker thread. This also lets you pass arguments to the callback and even return a value (such as a go/no-go flag). In your callback you update the UI through the target control's Dispatcher:
public void UpdateUI(object arg)
{
controlToUpdate.Dispatcher.BeginInvoke(
System.Windows.Threading.DispatcherPriority.Normal
, new System.Windows.Threading.DispatcherOperationCallback(delegate
{
controToUpdate.property = arg;
return null;
}), null);
}
}

Related

Thread calling problems

I'm a bit of a newbie at this but I am trying to get the UI on a Reversi game to run on a different thread to the move selection part but I am having some trouble calling the thread on the button click
private void playerMoveOKButton_Click(object sender, EventArgs e)
{
ReversiT.Invoke();
}
public void ReversiT() {...}
If you're trying to create a new thread, you can do something like this:
Thread thread = new Thread(ReversiT);
thread.Start();
Invoke is used for a different purpose though. It is used to run a method on a specific thread (for instance, if you run a piece of code on a separate thread but want to make UI changes, you will want to use Invoke to make those changes on the UI thread)
I would create a BackgroundWorker to handle everything for me, setting it's DoWork event to call your move method (making sure that your move method doesn't touch the UI, or if it has to, invoking the controls on the UI thread).
I'd also set up a method to update the UI on the BackgroundWorker's RunWorkerCompleted event.
Now on your button click event above, call the BGW's RunWorkerAsync() method.
You can not invoke a method like that. You can only invoke delegates. Also, calling Invoke doesn't spawn a new thread.
You can read this tutorial about delegates, and this one about threads. Also, your question leaves much space for discussion:
What do you expect from using threads?
Have you considered different options for doing background work?
etc.
Use following
this.Invoke(ReversiT);
I think you need to think about that you are actually trying to achieve here. Running code on a separate thread in a UI is a technique used to stop the UI from hanging. However, some tasks simply have to occur on the UI thread and so can't be run from another thread.
You need to break your logic out such that you can identify which parts need to run on the UI thread (anything that interacts with a control on your UI) and thus anything that can run on a separate thread.
You would end up with code like (as an example):
private void playerMoveOKButton_Click(object sender, EventArgs e)
{
//thread is merely used as an example
//you could also use a BackgroundWorker or a task
var thread = new Thread(NonUiLogic);
thread.Start();
}
private void NonUiLogic()
{
...
//execute logic that doesn't touch UI
...
BeginInvoke(ReversiT);
}
public void ReversiT() {...}
Once you have been through that exercise you may find that there is actually very little that can happen outside of the UI thread and so you really have nothing to gain from using threads.

How do I call a function in a threadsafe manner

I have been playing around with methods of calling of calling a method safely in threadsafe manner in .net 2.0.
My treeview is populated from a call to a database on a separate thread;
Below is my attempt to use my InvokeFunction method ( shown below) ...it works, but I was hoping that there was a nicer way to write this...any thoughts on this?
InvokeFunction(delegate() { TreeView1.Nodes.Clear(); });
delegate void FunctionDelegate();
private delegate void ThreadSafeProcess(FunctionDelegate func);
private void InvokeFunction(FunctionDelegate func)
{
if (this.InvokeRequired)
{
ThreadSafeProcess d = new ThreadSafeProcess(InvokeFunction);
this.Invoke(d, new object[] { func });
}
else
{
func();
}
}
BackgroundWorker is a cleaner solution in .NET 2.0.
It will create a thread for you and take care of synchronization.
You add BackgroundWorker component to you Form in the design mode.
You subscribe to DoWork event. The method subscribed to this will be execute in a background thread when you call backgroundWorker.RunWorkerAsync() in your UI thread.
When you need to interact with UI thread from your background thread you call backgroundWorker.ReportProgress.
This will trigger ProgressChanged event. ProgressChanged event is always executed in UI thread.
You can use userState parameter of backgroundWorker.ReportProgress to pass any data to UI thread. For example in your case the data that is needed to add new TreeView nodes.
You will actually add new nodes inside of ProgressChanged event handler.
Here is the link to MSDN: http://msdn.microsoft.com/en-us/library/system.componentmodel.backgroundworker.aspx.
Keep in mind you don't have to use percentProgress parameter of the method ReportProgress method. Although it is convenient when you have a progress bar to reflect background work progress.
You dont have to worry abbout thread safety unless you share some state. Functions always receive their parameters on the stack and stack is local for each thread. So functions are not your problem. Instead focus on the state. "TreeView1" objects is a candidate to worry about.

Windows Client GUI Design Advice - Accessing UI Thread from Long Running Task

Web Developer here and need some advice on how to achieve what must be a common requirement in Windows Forms.
I have a windows client app that calls a business object in a separate project to perform some long running tasks. Difference to other examples is that the process live in another class library i.e. Business.LongRunningTask();
I have a list box in the client that I would like to have logged to by the task. I can run the process on the UI thread passsing in the instance of the textbox and calling Application.DoEvents() when I log to the textbox from within the task. All fine, but not elegant and would prefer not to call Application.DoEvents();
If I run the long running process on a separate thread using delegates I cannot access the textbox or delegates created in the windows client form which rules out BeginInvoke calls.
Surely this is bad design on my part and would appreciate some feedback.
You're looking for the BackgroundWorker class.
To execute a time-consuming operation in the background, create a BackgroundWorker and listen for events that report the progress of your operation and signal when your operation is finished.
You can find a complete example here: http://msdn.microsoft.com/en-us/library/b2zk6580(v=VS.100).aspx#Y1351
I can run the process on the UI thread
passsing in the instance of the
textbox and calling
Application.DoEvents() when I log to
the textbox from within the task.
Yes, you could also pass in an instance of ILoggingINnterface that you have used to put in the code to write to the text box FROM WITHIN THE UI and thus have taken care of all the nice BginInvoke stuff ;)
If I run the long running process on a
separate thread using delegates I
cannot access the textbox or delegates
created in the windows client form
which rules out BeginInvoke calls.
Ah. No. You just most invoke back to the dispatcher thread then you can access all the UI elemente you like.
Yeah, avoid Application.DoEvents().
To marshall the call back onto the UI thread, call this.Invoke(YourDelegate)
To access UI elements from a different thread, you can use control.Invoke to call a delegate on the owning thread.
I used this at one point to create a live log screen which was updated from a timer while a different worker thread was running. Heres a simplified version:
public class DifferentClassLibrary
{
public delegate void StringDataDelegate(string data);
public event StringDataDelegate UpdatedData;
public void DoStuff()
{
if (UpdatedData != null)
{
Thread.Sleep(10000);
UpdatedData("data");
}
}
}
And in the winform:
public void UpdateTextBoxCallback(string data)
{
if (uiTextBoxLiveLogView.InvokeRequired)
{
uiTextBoxLiveLogView.Invoke(new DifferentClassLibrary.StringDataDelegate(UpdateTextBoxCallback), data);
}
else
{
uiTextBoxLiveLogView.Text += data;
}
}
void Main()
{
DifferentClassLibrary test = new DifferentClassLibrary();
test.UpdatedData += UpdateTextBoxCallback;
Thread thread = new Thread(new ThreadStart(test.DoStuff));
thread.Start();
}

C# Multi threading- Move objects between threads

i am working with a winforms control that is both a GUI element and also does some internal processing that has not been exposed to the developer. When this component is instantiated it may take between 5 and 15 seconds to become ready so what i want to do is put it on another thread and when its done bring it back to the gui thread and place it on my form. The problem is that this will (and has) cause a cross thread exception.
Normally when i work with worker threads its just with simple data objects i can push back when processing is complete and then use with controls already on the main thread but ive never needed to move an entire control in this fashion.
Does anyone know if this is possible and if so how? If not how does one deal with a problem like this where there is the potential to lock the main gui?
You don't need to lock the GUI, you just need to call invoke:
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. ref
Here is how it looks in code:
public delegate void ComponentReadyDelegate(YourComponent component);
public void LoadComponent(YourComponent component)
{
if (this.InvokeRequired)
{
ComponentReadyDelegate e = new ComponentReadyDelegate(LoadComponent);
this.BeginInvoke(e, new object[]{component});
}
else
{
// The component is used by a UI control
component.DoSomething();
component.GetSomething();
}
}
// From the other thread just initialize the component
// and call the LoadComponent method on the GUI.
component.Initialize(); // 5-15 seconds
yourForm.LoadComponent(component);
Normally calling the LoadComponent from another thread will cause a cross-thread exception, but with the above implementation the method will be invoked on the GUI thread.
InvokeRequired tells you if:
the caller must call an invoke method
when making method calls to the
control because the caller is on a
different thread than the one the
control was created on.
ref
Update:
So if I understand you correctly the control object is created on a thread other than the GUI thread, therefore even if you were able to pass it to the GUI thread you still won't be able to use it without causing a cross-thread exception. The solution would be to create the object on the GUI thread, but initialize it on a separate thread:
public partial class MyForm : Form
{
public delegate void ComponentReadyDelegate(YourComponent component);
private YourComponent _component;
public MyForm()
{
InitializeComponent();
// The componet is created on the same thread as the GUI
_component = new YourComponent();
ThreadPool.QueueUserWorkItem(o =>
{
// The initialization takes 5-10 seconds
// so just initialize the component in separate thread
_component.Initialize();
LoadComponent(_component);
});
}
public void LoadComponent(YourComponent component)
{
if (this.InvokeRequired)
{
ComponentReadyDelegate e = new ComponentReadyDelegate(LoadComponent);
this.BeginInvoke(e, new object[]{component});
}
else
{
// The component is used by a UI control
component.DoSomething();
component.GetSomething();
}
}
}
Without knowing too much about the object. To avoid cross thread exceptions, you can make the initial thread invoke a call (Even if you are calling from a thread).
Copied and pasted from one of my own applications :
private delegate void UpdateStatusBoxDel(string status);
private void UpdateStatusBox(string status)
{
listBoxStats.Items.Add(status);
listBoxStats.SelectedIndex = listBoxStats.Items.Count - 1;
labelSuccessful.Text = SuccessfulSubmits.ToString();
labelFailed.Text = FailedSubmits.ToString();
}
private void UpdateStatusBoxAsync(string status)
{
if(!areWeStopping)
this.BeginInvoke(new UpdateStatusBoxDel(UpdateStatusBox), status);
}
So essentially the threaded task will call the "Async" method. Which will then tell the main form to begininvoke (Actually async itself).
I believe there is probably a shorter way to do all of this, without the need for creating delegates and two different methods. But this way is just ingrained into me. And it's what the Microsoft books teach to you do :p
The BackgroundWorker class is designed for exactly this situation. It will manage the thread for you, and let you start the thread, as well as cancel the thread. The thread can send events back to the GUI thread for status updates, or completion. The event handlers for these status and completion events are in the main GUI thread, and can update your WinForm controls. And the WinForm doesn't get locked. It's everything you need. (And works equally well in WPF and Silverlight, too.)
The control must be created and modified from the UI thread, there's no way around that.
In order to keep the UI responsive while doing long-running initialization, keep the process on a background thread and invoke any control access. The UI should remain responsive, but if it doesn't, you can add some wait time to the background thread. This is an example, using .Net 4 parallel tools: http://www.lovethedot.net/2009/01/parallel-programming-in-net-40-and_30.html
If interaction with the specific control being initialized can't be allowed until initialization finishes, then hide or disable it until complete.

synchronize threads - no UI

I'm trying to write multithreading code and facing some synchronization questions. I know there are lots of posts here but I couldn't find anything that fits.
I have a System.Timers.Timer that elapsed every 30 seconds it goes to the db and checks if there are any new jobs. If he finds one, he executes the job on the current thread (timer open new thread for every elapsed). While the job is running I need to notify the main thread (where the timer is) about the progress.
Notes:
I don't have UI so I can't do beginInvoke (or use background thread) as I usually do in winforms.
I thought to implement ISynchronizeInvoke on my main class but that looks a little bit overkill (maybe I'm wrong here).
I have an event in my job class and the main class register to it and I invoke the event whenever I need but I'm worrying it might cause blocking.
Each job can take up to 20 minutes.
I can have up to 20 jobs running concurrently.
My question is:
What is the right way to notify my main thread about any progress in my job thread?
Thanks for any help.
You can also use lock to implement a thread-safe JobManager class that tracks progress about the different worker threads. In this example I just maintain the active worker threads count, but this can be extended to your progress reports needs.
class JobManager
{
private object synchObject = new object();
private int _ActiveJobCount;
public int ActiveJobsCount
{
get { lock (this.synchObject) { return _ActiveJobCount; } }
set { lock (this.synchObject) { _ActiveJobCount = value; } }
}
public void Start(Action job)
{
var timer = new System.Timers.Timer(1000);
timer.Elapsed += (sender, e) =>
{
this.ActiveJobsCount++;
job();
this.ActiveJobsCount--;
};
timer.Start();
}
}
Example:
class Program
{
public static void Main(string[] args)
{
var manager = new JobManager();
manager.Start(() => Thread.Sleep(3500));
while (true)
{
Console.WriteLine(manager.ActiveJobsCount);
Thread.Sleep(250);
}
}
}
You can notify the main thread of progress through a callback method. That is:
// in the main thread
public void ProgressCallback(int jobNumber, int status)
{
// handle notification
}
You can pass that callback method to the worker thread when you invoke it (i.e. as a delegate), or the worker thread's code can "know" about it implicitly. Either way works.
The jobNumber and status parameters are just examples. You might want you use some other way to identify the jobs that are running, and you may want to use an enumerated type for the status. However you do it, be aware that the ProgressCallback will be called by multiple threads concurrently, so if you're updating any shared data structures or writing logging information, you'll have to protect those resources with locks or other synchronization techniques.
You can also use events for this, but keeping the main thread's event subscriptions up to date can be a potential problem. You also have the potential of a memory leak if you forget to unsubscribe the main thread from a particular worker thread's events. Although events would certainly work, I would recommend the callback for this application.
Use events. The BackgroundWorker class, for example, is designed specifically for what you have in mind.
http://msdn.microsoft.com/en-us/library/system.componentmodel.backgroundworker.aspx
The ReportProgress function along with the ProgressChanged event are what you would use for progress updates.
pullJobTimer.Elapsed += (sender,e) =>
{
BackgroundWorker worker = new BackgroundWorker();
worker.WorkerReportsProgress = true;
worker.DoWork += (s,e) =>
{
// Whatever tasks you want to do
// worker.ReportProgress(percentComplete);
};
worker.ProgressChanged += mainThread.ProgressChangedEventHandler;
worker.RunWorkerAsync();
};
If you don't mind depending on .NET 3.0 you can use the Dispatcher to marshal requests between threads. It behaves in a similar way to Control.Invoke() in Windows Forms but doesn't have the Forms dependency. You'll need to add a reference to the WindowsBase assembly though (part of .NET 3.0 and newer and is basis for WPF)
If you can't depend on .NET 3.0 then I'd say you were onto the correct solution from the beginning: Implement the ISynchronizeInvoke interface in your main class and pass that to the SynchronizingObject property of the Timer. Then your timer callback will be called on the main thread, which can then spawn BackgroundWorkers that checks the DB and runs any queued jobs. The jobs would report progress through the ProgressChanged event which will marshal the call to the main thread automatically.
A quick google search revealed this example on how to actually implement the ISynchronizeInvoke interface.

Categories

Resources