Updating UI after running background work with parallel.Invoke - c#

I'm running heavvy background work with Parallel.Invoke, after all processing has completed I return the method, return again, call a next method to utilize the calculated data I get the error:
Cross-thread operation not valid: Control '' accessed from a thread other than the thread it was created on.
But I already returned from the threads that where created by Parallel.Invoke to the one that called it in the first place. Is it normal that control does not revert to the thread where it started? And how can I assure that this does happen?
Code:
public void TopMethod()
{
Calculate(4);
UpdateGui();
}
public void Calculate(int depth)
{
Recursive(depth);
}
public void Recursive(int depth)
{
if (depth > 0)
System.Threading.Tasks.Parallel.Invoke(
delegate { Recursive(depth - 1); });
}
public void UpdateGui()
{
CalculateOhter(); // Works fine.
controlElement.Focus(); // Causes exception
}
Edits:
I know about Control.Invoke But this would be an ugly solution (don't want to store a delegate in every control) and the program needs to wait for all computations to complete before it can continue. So it would be better if I could somehow force control to return to the thread that I started out with in the first place.

You need to access a control/window from the thread that created that control. Use Control.Invoke and Control.InvokeRequired.

The horrible way to do is to set Control.CheckForIllegalCrossThreadCalls to false. It should get rid of your error, but it is not good design.
The problem with that occurs when a thread other than the creating thread of a control tries to access one of that control's methods or properties, it often leads to unpredictable results.

The example for Control.Invoke involves storing a Delegate, can this be done without storing a delegate for every control? So passing the method I need to call as an argument to the Invoke call (tried this but cannot get it to work).
The program needs to wait for all computations to complete before it can continue so it would be better if I could somehow force control to return to the thread that I started out with in the first place.
I don't understand why this does not happen at default, why does it not just return to the thread it started with when everything is complete?

Solved it, turns out I created a seperate thread to call the given code in the first place, kinda stupid :P

Related

How to Invoke multiple controls in C#

I have a C# program seems stuck at random time, and after a random while it recovered itself! When it stuck, I can see the memory growth, and when it recover, the memory usage just drops to normal. The CPU usage seems normal all the way and there is no files is written or read (as designed).
The program calls an external (3rd party) DLL function to communicate with hardware, and updates the UI from the DLL's callback which running on a different thread. I have checked the code and found nothing suspicious apart from the following code (redacted):
private void Func(StructType para) {
if (labelA.InvokeRequired) {
labelA.BeginInvoke(new MethodInvoker(() => Func(para)));
return;
}
if (labelB.InvokeRequired) {
labelB.BeginInvoke(new MethodInvoker(() => Func(para)));
return;
}
labelA.Text = para.A;
labelB.Text = para.B;
}
I wonder if this is a proper way of update the UI element from another thread? If not, how to revise it?
In fact, I invoke 6 labels and another form (optionally). It seems working fine for most time but occasionally stuck. I can't post all code here for obvious reason, but just trying to troubleshot from where I doubt most.
Thanks in advance for any suggestions!
You don't need to individually check each each control to determine if you need to invoke it - there is only one UI thread, thus, that check is only useful once. Keep in mind - modifying any UI component is almost certain to cascade into a whole bunch of other reads/writes to other UI components; as a result of that, you have to make the assumption that if you are touching any UI object, you have to assume you're touching all UI components.
With that in mind, I'd recommend you perform your invoke check once, and I recommend performing the check and invoke on the parent control of both labels.
Assuming this refers to the class that is the parent to both those labels, I would modify your code as follows:
private void Func(StructType para) {
if (this.InvokeRequired) {
// Elide the explicit delegate declaration; it's not necessary.
this.BeginInvoke( Func(para) );
// Elide the return statement - multiple returns are messy, and in this case, easily removed.
}
else {
labelA.Text = para.A;
labelB.Text = para.B;
}
}
Be aware that InvokeRequired returns false if the object is disposed, even if the calling thread is not the UI thread.

Setting text boxes thread issues

I'm pretty new at C# so forgive me if this is a bit of a silly question.
Anyway I'm writing a little chat application that so far seems to be going well, I've run into a problem that I seem to have fixed but I'm hoping to work out why I need to do it this way.
When I receive a message I want to update a text box so I use:
txtConnectedID.Text = "test";
But I receive this error:
System.InvalidOperationException was unhandled by user code
Message=Cross-thread operation not valid: Control 'txtConnectedID' accessed from a thread other than the thread it was created on.
Now, I think this has something to do with stopping the method running twice and not updating properly? I'm not 100% on this. So now I have a delegate for a method that accepts a string and I call:
private delegate void stringDelegate(string s);
BeginInvoke(new stringDelegate(writeToIPBox), new object[] { e.ConnectedIP.ToString() });
private void writeToIPBox(string newIP)
{
txtConnectedID.Text = newIP;
}
I'm not sure why I'm doing this, how it's any different. I'm not really happy to just do it this way without knowing why.
Thanks in advance
You should only attempt to update controls from the thread on which they were created. There are good reasons for this as it is easy to hit a race condition. These controls are not thread safe and this is the runtime helping you out a bit.
Instead, as you have figured out, you need to update it on the UI thread, which is what BeginInvoke is doing; calling the delegate asynchronously on the UI thread.
All controls are owned by the UI thread (of which there is only one), and trying to access them from another thread results in this Exception.
BeginInvoke calls the specified delegate on the UI thread, which is why it works. You can also check if you are on the UI thread by checking txtConnectedID.InvokeRequired.
It took a new minutes of determined googling but I eventually found an "authorative" reference:
http://msdn.microsoft.com/en-us/library/system.windows.forms.control.invokerequired%28v=vs.90%29.aspx
The short answer (to quote from that page) is: Controls in Windows Forms are bound to a specific thread and are not thread safe.
This article also aludes to how this can be handled "internally"... if control.InvokeRequired (i.e. we've been called from another thread) handle the invocation internally... rather than spreading delegates throughout your code.
Personally I'd never really questioned WHY a delegate was required, I just did it. Good question.
Cheers. Keith.
private static void SetText(TextBox tb, string text)
{
if (tb.InvokeRequired)
{
var stDelegate = new StDelegate(SetText);
tb.Invoke(stDelegate, new object[] { tb, text });
}
else
{
tb.Text = text;
}
}

C# multithreading - updating the GUI with background events

I'm a newbie to C# and multithreading so I apologise if this is a duplicate question but being a novice it appears my question is slightly different to others I have read.
My GUI runs in one (main) thread. It calls a background task (in a dll -- that I am writing too) that runs in a separate thread. The dll has NO knowledge of the GUI (i.e. it cannot reference the GUI class).
Now, say I want to update a progress bar on the GUI based on the status of the dll thread -> What I'm doing is creating an event in the dll that every X per cent will fire and the GUI will subscribe to this event. When the event is fired, the GUI will update the progress bar.
My questions:
Is the method of creating events the best way (bearing in mind the dll cannot reference the GUI)?
How do I ensure my above method is 'event safe'? Should I pass the progress percentage in the event to be thread safe or is there more to it?
Do I need to use Invoke when updating the GUI? I saw a post that suggested I did but I don't understand why since the updating of the bar is being done in the GUI thread??!
Hope you can clarify this for me!
Thanks
1.-I use that method all the time and yes it will work
2.-Just pass a int to the event handler and the variable will be safe to read. however when you are fireing the event from code do it like this
private void UpdatePercentage(int a)
{
var myEvent = PercentageUpdatedEvent
if(myEvent != null)
myEvent(this, new ProgressBarEventArgs(a));
}
The reason for this is so if the event is unsubcribed between the null check and the calling you won't get a exception.
3.-As everyone else has mentioned you will need to call Invoke as the event will be running on the dll's thread. However with controls it is legal to call a BeginInvoke without a EndEnvoike so the call will be non blocking on the dll's thread.
Here is the pattern I always use
private myClass_OnPercentageUpdatedEvent(object a, ProgressBarEventArgs e)
{
if(progressBar.InvokeRequired)
progressBar.BeginInvoke((Action<object,ProgressBarEventArgs>)myCless_OnPercentageUpdatedEvent, a, e);
else
{
progressBar.Value = e.Value;
}
}
Look into the BackgroundWorker class. It sounds like it fits your scenario pretty well.
This link on MSDN explains how to use it: http://msdn.microsoft.com/en-us/library/cc221403%28VS.95%29.aspx
Keep in mind that under most circumstances, the events raised from your background task will also run on the background thread. No thread context switch happens automatically at all.
To understand why, you have to consider what an event is; just a certain type of Delegate object. You are setting a Delegate to that event from the main thread... but that delegate will actually be called within the background thread, in the code that triggers the event.
So yes; you would need to make sure you are moving things over to run on the GUI thread from within that event handler.
To answer (3) you will need to use Invoke. The event-handlers are going to be run from the background thread, not the GUI thread.
If you spin off a thread, you need to create a delegate, that can safely invoke your main thread with the appropriate parameters.
delegate void UpdateDelegate(int val)
void Update(int val)
{
if(this.InvokeRequired())
{
Invoke(new UpdateDeleage(Update),new object[] {val});
return;
}
this.MyProgressBar.Value = val;
}
Call Update from your separate thread as you would if calling it from your main thread. Once the thread determines that your main thread needs invoked to pass the value, it will invoke it with your delegate, with the parameters you passed. Otherwise, it will simply skip the block and set your values.
e.g.
...
new Thread(()=>IncrementValues()).Start();
...
void IncrementValues()
{
while(true)
Update(new Random(0,10));
}
I have on my blog a few different approaches to this problem, with the advantages/disadvantages of each. In summary, I recommend using the Task class.

Using VerifyAccess and CheckAccess methods of DispatcherObject

While going through this article I came across this statement -
If you are writing your own WPF
objects, such as controls, all methods
you use should call VerifyAccess
before they perform any work. This
guarantees that your objects are only
used on the UI thread, like this
//Using VerifyAccess and CheckAccess
public class MyWpfObject : DispatcherObject
{
public void DoSomething()
{
VerifyAccess();
// Do some work
}
public void DoSomethingElse()
{
if (CheckAccess())
{
// Something, only if called
// on the right thread
}
}
}
I haven't seen this in any of the custom controls I have come across(as far as I remember).
Do you use this while building custom controls?
Is it must to do this or just nice to have?
Anyone ever faced any issue due to absence of this in your controls?
Nah, never used this. And never noticed somebody use it in the context of Custom Controls. This rule is not followed in WPF Toolkit too.
This approach not only pollutes the code but also makes your custom control responsible for something it shouldn't care about. Consider situation where you always doing:
// Don't do this in all methods of your custom control!
public void Foo()
{
if (!CheckAccess())
{
Dispatcher.Invoke(()=> Foo()); // Transit to UI Thread
return;
}
// .. do work in UI.
}
At first glance this code looks fine. If you are not in UI thread, transit to UI thread, perform operation and return result. Right? - WRONG!
Problem 1. When you call Dispatcher.Invoke() you block calling thread until your request is processed by UI thread. This leads to poor performance. Of course, you can change this to Dispatcher.BeginInvoke() now your clients should be aware that their operation is done asynchronously. I.e. if client writes something to control, and then immediately reads it back there is no guarantee, that the operation already executed by UI thread.
Problem 2. Consider subsequent calls to the method Foo() from non UI thread. For example it's called in cycle:
// Somewhere not in UI
for (int i = 0; i < 1000000; i++)
{
control.Foo(); // Looks good, but performance is awful!
}
Instead of blocking calling thread 1000000 times, developer could implement one check in the calling thread and transit to UI when necessary, instead of unconsciously jumping back and worth between threads.
Furthermore WPF will make this check for you when you access UI element from non-UI thread. It screams loud enough to crush application and be heard by developer who has done something wrong :).
Hope this helps.

How do I halt outdated UI updates?

Let's say I have a C# program with a GUI, and the update/refresh/display of the GUI takes 0.2 seconds.
Say, while it is still computing the display process (within this 0.2 seconds), a new update request is given, so the current one is outdated. How can I make it stop doing this meaningless outdated work to start computing for the new request?
It might not be only about UI update too. Perhaps, for any function call, how can I make it so it will become "If another of the same call is issued, abandon the current work and go with the new data/situation instead"?
Thanks.
Perhaps, for any function call, how can I make it so it will become "If another of the same call is issued, abandon the current work and go with the new data/situation instead"?
Why would you want that? You would lose all provability in your code. You would never be able to ensure a consistent state in your system. If you want to simulate it, just mess with the PC. Design a program that arbitrarily pushes the PC back to the top of any method that it is in. You would quickly see the system devolve.
You're talking about some fairly advanced threading issues. Using the built-in system control structure, there's no way to prevent the message loop from completing any more than there is a method for interrupting (gracefully) another method.
Now, if this capability is very important to you, you COULD build all custom controls and within your control's painting code you could check (in a thread-safe manner, of course) a boolean value indicating whether or not painting should continue.
But if I can take a stab in the dark, I'm going to guess that you're not actually explicitly doing any multithreading. If this is the case, then the scenario that you describe can't ever actually happen, as the process of refreshing the GUI is going to complete before another one can begin (namely, this anonymous process you're describing that calls for another refresh or deems the current one stale). Because code on the same thread executes sequentially, there's really no opportunity for an unrelated piece of code to cause an update.
The semantics of how and when repaints take place (the difference between Invalidate() and Refresh(), and their respective impacts on this logic, for example) is a topic that's probably really not of interest to you. Just know that if you're...
Doing multithreading, then you'll
have to implement your own code for
checking whether or not the current
operation should continue (for the
UI, this means custom controls with
this logic in the paint logic)
Not
doing multithreading, then what you
describe can never happen.
Hope this is helpful!
One possible way is to start off a thread that updates the GUI and abort it and start another. This is generally not a recommended practice because of the horrible state of thread management in C# but you should be able to get around it without worrying.
public static class ControlExtensions
{
public static TResult InvokeEx<TControl, TResult>(this TControl control,
Func<TControl, TResult> func)
where TControl : Control
{
if (control.InvokeRequired)
return (TResult)control.Invoke(func, control);
else
return func(control);
}
}
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
Thread guiUpdateThread = null;
public void BeginLongGuiUpdate(MyState state)
{
if (guiUpdateThread != null && guiUpdateThread.ThreadState != ThreadState.Stopped)
{
guiUpdateThread.Abort();
guiUpdateThread.Join(); // wait for thread to abort
}
guiUpdateThread = new Thread(LongGuiUpdate);
guiUpdateThread.Start(state);
}
private void LongGuiUpdate(object state)
{
MyState myState = state as MyState;
// ...
Thread.Sleep(200);
this.InvokeEx(f => f.Text = myState.NewTitle);
// ...
}
}
I don't knwo if this maps to what you need, but here goes.
One way to achieve this kind of behavior is to reverse the problem and delay the actual rendering.
Any time you get a request or change, fire off a timer. Every request coming in will either start or restart the time.
When the timer actually elapses, carry out the rendering.
It does not do exactly what you describe, but it might actually do what you need in the end, which is not to render for each request because rendering takes too long.
If you do not have continuous requests, this works fairly well. Obviously, if you do, you never get anything displayed...

Categories