I am new to C#, i have read something about threading like begininvoke and eventhandler stuff. but could you explain what's the following code is doing on the richtextbox?
private void Log(LogMsgType msgtype, string msg)
{
rtfTerminal.Invoke(new EventHandler(delegate
{
rtfTerminal.SelectedText = string.Empty;
rtfTerminal.SelectionFont = new Font(rtfTerminal.SelectionFont, FontStyle.Bold);
rtfTerminal.SelectionColor = LogMsgTypeColor[(int)msgtype];
rtfTerminal.AppendText(msg);
rtfTerminal.ScrollToCaret();
}));
}
*is this Invoke similiar to begininvoke?
* in the msdn, it describe it as Executes the specified delegate on the thread that owns the control's underlying window handle.Not quite sure about the meaning of it.
could you explain what's the following code is doing on the richtextbox?
It executes the code in the anonymous method on the UI thread.
is this Invoke similiar to begininvoke?
Yes, but Invoke is synchronous, whereas BeginInvoke is asynchronous. In other words, a call to Invoke will block until the UI thread executes the specified action, whereas BeginInvoke will return immediately, without waiting for the action to be executed by the UI thread.
in the msdn, it describe it as Executes the specified delegate on the thread that owns the control's underlying window handle.Not quite sure about the meaning of it.
In Windows Forms, controls can only be accessed on the thread that created them. So if you're executing something on a different thread, and you perform an action on a control from this thread, you can't do it directly; you need to ask the UI thread to perform this action. That's what Invoke and BeginInvoke are for.
Related
My program has 2 threads running, thread 1 does something to control a label in a form running on thread 2. So I have to use a delegate and invoke a function in form 1 class to access the label. My code is below and it works perfectly. However, I'm wondering if there is a shorter, better way to do this?
delegate void Change_Status_Call_Back(string status_changed);
public void change_status(string status_changed)
{
if (this.label_status.InvokeRequired)
{
Change_Status_Call_Back obj = new Change_Status_Call_Back(change_status);
this.Invoke(obj, new object[] { status_changed });
}
else
{
this.label_status.Text = status_changed;
}
}
This question is "primarily opinion based". Still, you've touched a pet peeve of mine, so…
You should skip the InvokeRequired check altogether:
public void change_status(string status_changed)
{
this.Invoke((MethodInvoker)(() => this.label_status.Text = status_changed));
}
The framework has to effectively check InvokeRequired anyway, because it's required to support invoking on the UI thread without deadlocking. So the check in your code is redundant. The overhead of always wrapping the method body in a delegate invocation is inconsequential in UI code like this, especially since if you're writing this code, it's probably the case that the method's not going to be called exception when InvokeRequired would be true anyway (i.e. the "fast path" is never taken anyway).
Even better is to use a more modern mechanism for dealing with cross-thread access, such as async/await or the Progress<T> class. Then you never have to write an explicit call to Invoke() at all.
Some time ago, I ranted in more depth here: MSDN’s canonical technique for using Control.Invoke is lame
I would do this:
public void change_status(string status_changed)
{
this.label_status.InvokeSafely(c => c.Text = status_changed);
}
You need this extension method:
public static void InvokeSafely(this Control control, Action<Control> action)
{
if (control.InvokeRequired)
{
control.Invoke((Action)(() => action?.Invoke(control)));
}
else
{
action?.Invoke(control);
}
}
After looking around, I came up with this:
// UPDATE DISPLAY items (using Invoke in case running on BW thread).
IAsyncResult h = BeginInvoke((MethodInvoker)delegate
{
FooButton.Text = temp1;
BarUpdown.Value = temp2;
}
);
EndInvoke(h); // Wait for invoke to complete.
h.AsyncWaitHandle.Close(); // Explicitly close the wait handle.
// (Keeps handle count from growing until GC.)
Details:
I removed if (InvokeRequired) completely. (Discovered from Peter Duniho's answer here.) Invoke() works just fine on the UI thread. In code that runs only on the UI thread, UI actions need no special treatment. In code that runs only on a non-UI thread, wrap all UI actions in an Invoke(). In code that can run on the UI thread -or- a non-UI thread, likewise wrap all UI actions in an Invoke(). Always using Invoke() adds some overhead when running on the UI thread, but: not much overhead (I hope); the actions run less often on the UI thread anyway; and by always using Invoke, you don't have to code the UI actions twice. I'm sold.
I replaced Invoke() with BeginInvoke() .. EndInvoke() .. AsyncWaitHandle.Close(). (Found elsewhere.) Invoke() probably just does BeginInvoke() .. EndInvoke(), so that much is just inline expansion (slightly more object code; slightly faster execution). Adding AsyncWaitHandle.Close() addresses something else: When running on a non-UI thread, Invoke() leaves hundreds of handles that linger until garbage collection. (It's scary to watch Handles count grow in Task Manager.) Using BeginInvoke() .. EndInvoke() leaves lingering handles just the same. (Surprise: Using only BeginInvoke() does not leave the handles; it looks like EndInvoke() is the culprit.) Using AsyncWaitHandle.Close() to explicitly kill the dead handles eliminates the [cosmetic] problem of lingering handles. When running on the UI thread, BeginInvoke() .. EndInvoke() (like Invoke()) leaves no handles, so AsyncWaitHandle.Close() is unnecessary, but I assume it is also not costly.
An IsDisposed test seems safe against race conditions, but I think it is not necessary. I'm worried that BackgroundWorker can Invoke() the operation; while it is pending, a click can trigger a callback on the UI thread that can Close() the form, and then the message loop executes this operation. (Not sure this can happen.)
Problem: (I will update here when something works.) I changed all my UI updates from running on a UI timer kludge to using Invoke() (as above), and now closing the form fails on a race condition about 20% of the time. If a user click stops my background worker, clicking on close after that works fine. BUT, if the user clicks directly on close, that triggers a callback on the UI thread which Close()s the form; that triggers another that flags the background worker to stop; the background worker continues, and it crashes at EndInvoke() saying "Cannot access a disposed object. Object name: 'MainWin'. at System.Windows.Forms.Control.MarshaledInvoke(Control caller, Delegate method, Object[] args, Boolean synchronous) ...". Adding if (!this.IsDisposed) {} around EndInvoke() .. AsyncWaitHandle.Close() doesn't fix it.
Option: Go back to using a forms timer: Make the BW write its changes into a dozen global "mailbox" variables. Have the timer do FooButton.Text = nextFooButtonText;, etc. Most such assignments will do almost nothing because setting a form field only updates the display if the value actually changes. (For clarity and to reduce copying objects, initialize the mailbox variables to null, and have the timer do if (nextFooButtonText != null) { FooButton.Text = nextFooButtonText; nextFooButtonText = null; }, etc.) The timer puts a new event on the UI message loop every so many milliseconds, which is more silly grinding than the Invoke()s. Updating the display on a timer callback delays each update by [up to] the timer interval. (Yuck.)
WORKING Option: Use only BeginInvoke(). Why make BW wait for each Invoke to finish? 1) temp1 and temp2 seem passed as references - if they get changed after BeginInvoke(), the new value wins. (But that's not so bad.) 2) temp1 and temp2 can go out of scope. (But aren't they safe against being released until the last reference goes away?) 3) Waiting ensures that BW only has one invoked action pending at a time - if the UI thread blocks for a while, BW can't bury it in events. (But my UI thread can't block, at least not at times when my BW is running.)
Option: Put try .. catch around the EndInvoke(). (Yuck.)
I have seen several other tricks suggested:
•Have Close cancel itself, initiate a timer, and then return so that any lingering Invoke()s finish on the UI thread; shortly after that the timer callback does a real Close (found here; from here).
•Kill the background worker thread.
•Alter Program.cs to shut down differently.
I originally tried to use the Dispatcher class BeginInvoke method to show a message box on the main UI thread in my C# Windows Forms app. When I used that method the message box did not appear. I set a breakpoint inside the body of the delegate I passed to BeginInvoke() and it was never hit. I tried using both an Action delegate and a MethodInvoker delegate. No luck in either case.
When I used the BeginInvoke method belonging to the Form object it worked fine. Why did the Dispatch version fail silently (no exceptions or error messages)? Below are the two different versions.
Dispatcher dispatcher = Dispatcher.CurrentDispatcher;
// THIS FAILED. CONTEXT: Executing on worker thread.
MethodInvoker theMethod = new MethodInvoker(delegate()
{
string msg = "Show this message on the main UI thread.";
MessageBox.Show(msg, "Message");
});
dispatcher.BeginInvoke(theMethod);
this.BeginInvoke(theMethod);
// ---------------------------------------------------
// THIS WORKED. CONTEXT: Executing on worker thread.
MethodInvoker theMethod = new MethodInvoker(delegate()
{
string msg = "Show this message on the main UI thread.";
MessageBox.Show(msg, "Message");
});
// "this" is a Form object.
this.BeginInvoke(theMethod);
If I'm reading your comments correctly, you are calling Dispatcher.CurrentDispatcher from a non-UI thread. This is not how this is meant to be used.
As the documentation for Dispatcher.CurrentDispatcher says:
Gets the Dispatcher for the thread currently executing and creates a new Dispatcher if one is not already associated with the thread.
To get a valid dispatcher instance, you need to call Dispatcher.CurrentDispatcher from the UI thread.
Also, because the documentation says that it will automatically create a dispatcher if one does not exist for the current thread, this is what explains the silent failure. You are getting a dispatcher instance, but it isn't associated to the UI thread in any way, so it isn't actually dispatching anything to the UI thread.
(Removing this, because in my tests, I get null even when I shouldn't, so it doesn't prove much it seems. The rest of the information is accurate though)
The documentation also adds:
This is not the case with the FromThread method. FromThread will return null if there is not a dispatcher associated with the specified thread.
So to confirm that you are indeed getting an auto-created (invalid) dispatcher, try getting the dispatcher from Dispatcher.FromThread instead. My guess is that you will get null.
If you want to call dispatcher.BeginInvoke to force execution of a method on the UI thread from a worker thread, you need to call Dispatcher.CurrentDispatcher from the UI thread and save that to a variable. You can then pass that dispatcher reference variable to the worker thread, and call BeginInvoke on that.
// capture and save dispatcher from UI thread
Dispatcher dispatcher = Dispatcher.CurrentDispatcher;
// then you can do this from your worker thread:
dispatcher.BeginInvoke(theMethod);
Alternatively, use this.BeginInvoke like you are doing already.
Or better yet, you can try using tasks combined with the new async-await keywords for this sort of thing.
EDIT
For completeness, I should explain why Control.BeginInvoke does work correctly.
As the documentation for Control.BeginInvoke says:
Executes the specified delegate asynchronously on the thread that the control's underlying handle was created on.
And later it also adds:
You can call this method from any thread.
The point is that, when you call Control.BeginInvoke, it doesn't use the current thread to determine how to execute the delegate. It remembers which thread the control was created on (the UI thread), and makes sure to execute the delegate on that thread.
So, as long as your control is created on the UI thread (as it should), then BeginInvoke works from any thread. This is actually quite similar to the Dispatcher in that, as long as you obtain the Dispatcher instance from the UI thread first, then you can call Dispatcher.BeginInvoke from any thread as well.
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.
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.
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.