Re: Making threadsafe calls : C# 2005
Adam Sills <[email protected]> Tue, 19 Jun 2007 14:01:47 -0500
| Newsgroups | gmane.comp.windows.devel.dotnet.cx |
|---|---|
| Message-ID | <[email protected]> |
For a lot of cases you'll likely be safe, but not all. In 1.0/1.1 very few controls threw this exception and didn't have any problems. Many things would work until you hit the one place that didn't work and then you'd have to synchronize. In 2.0 this exception is thrown a lot more and using that property to revert back to the 1.0/1.1 behavior is good, until you hit that one place that doesn't work. Then you'll have to synchronize that one part. An example of places I've had problems: forcing a control paint on a non-UI thread (self-drawn controls would blow up during Paint), manipulating list view items on a non-UI thread. I don't recall ever having issue with just the text of a text box or label (since, if I'm not mistaken ends up being a WM_SETTEXT message which will always execute on the UI thread). Adam.. -----Original Message----- From: Discussion relating to the specifics of the C# and Managed C++ languages [mailto:[email protected]] On Behalf Of Peter Osucha Sent: Tuesday, June 19, 2007 1:50 PM To: [email protected] Subject: Re: [DOTNET-CX] Making threadsafe calls : C# 2005 Thanks Adam. The 'SetText()' method was in the MSDN example. My form has methods like 'UpateStatusBar()', 'UpdateGridDisplay()', 'UpdateGraphDisplay()'. However, you are right in your assumption about the MSDN example's 'SetText' method. (Eddie, your suggestion is what I am doing though for some reason, it seems like 'cheating'). So perhaps a followup - how much does this really matter? Why not just set the property that 'ignores' these error messages? Peter -----Original Message----- From: Discussion relating to the specifics of the C# and Managed C++ languages [mailto:[email protected]] On Behalf Of Adam Sills Sent: Tuesday, June 19, 2007 2:44 PM To: [email protected] Subject: Re: [DOTNET-CX] Making threadsafe calls : C# 2005 Their threading example was just filler to get code running in a separate thread. The important method there is the SetText which likely creates a delegate and checks InvokeRequired. If you have a class/component that is raising events asynchronously on background threads and you are subscribing to those events, it's simpler (using your example): private void MyComponent_DataReceived( object sender, DataReceivedEventArgs e ) { if( this.InvokeRequired ) { this.Invoke( new DataReceivedEventHandler(MyComponent_DataReceived), sender, e ); return; } this.txtMyTextBox.Text = e.GetData(); } I can only assume that the SetTExt method looks like so (since you didn't include it): delegate void SetTextDelegate( string text ); private void SetText(string text) { if( this.InvokeRequired ) { this.SetText( new SetTextDelegate(SetText), text ); return; } this.txtMyTextBox.Text = text; } Notice that both are doing the exact same thing (4 lines of code including curly braces to perform this.Invoke), the only difference is your background component has already defined all the necessary delegates so you don't have to make one for every method you call. Another option you have is to use ISynchronizeInvoke inside your component. ISynchronizeInvoke defines the contract that has the InvokeRequied property and the Invoke method. Every Control derivative implements ISynchronizeInvoke. You can alter your component itself to accept an instance of ISynchronizeInvoke and let it do all that. public MyBackgroundComponent { private ISynchronizeInvoke m_Invoker; public MyBackgroundComponent( ISynchronizeInvoke invoker ) { m_Invoker = invoker; } protected void OnMyEvent( MyEventArgs e ) { if( m_Invoker != null && m_Invoker.InvokeRequired ) { m_Invoker.Invoke( new MyEventHandler(RaiseMyEvent), this, e ); return; } RaiseMyEvent( sender, e ); } private void RaiseMyEvent( object sender, MyEventArgs e ) { MyEventHandler h = this.MyEvent; h( sender, e ); } } Obviously this doesn't necessarily make it any easier, but it keeps the complexity out of your form instances. If you take a look at System.Timers.Timer, using ISynchronizeInvoke is how it invokes the handlers on the owner form's thread (through its SynchronizingObject property). Adam.. -----Original Message----- From: Discussion relating to the specifics of the C# and Managed C++ languages [mailto:[email protected]] On Behalf Of Peter Osucha Sent: Tuesday, June 19, 2007 1:25 PM To: [email protected] Subject: [DOTNET-CX] Making threadsafe calls : C# 2005 Hi guys, I occasionally forget (well more often than not I cheat and ignore the errors) to make threadsafe calls to form controls. A good example I am facing now - I have an object ('Instrument') that is handling messages from a connected actual hardware instrument by way of a TCP Socket connection. This Instrument object raises many events so that a subscribing form containing an object instance can provide feedback to the user. So I have reviewed the 'How to make thread safe calls to Windows Form Controls' topic in MSDN and I am puzzled by the example (or I just don't understand it well). The topic offers a code sample (shown below)... // This event handler creates a thread that calls a // Windows Forms control in a thread-safe way. private void setTextSafeBtn_Click( object sender, EventArgs e) { this.demoThread = new Thread(new ThreadStart(this.ThreadProcSafe)); this.demoThread.Start(); } // This method is executed on the worker thread and makes // a thread-safe call on the TextBox control. private void ThreadProcSafe() { this.SetText("This text was set safely."); } It seems that to implement this type of thread-safe calling will require a whole lot of code (it seems that I will need such a 'setup' for modifying each and every form control I want to modify. Maybe a more concrete example of what I'm talking about would be useful. My Instrument object raises among other events a 'DataReceived() event' which the form has a handler for. When this event is handled by the form, it updates several controls on the form. So I can see how I would create a 'demoThread' in the event handler that calls a separate method (similar to 'ThreadProcSafe' in the example above) but it seems that I'd have to call several different 'ThreadProcSafe' methods to handle all the controls updating I require. I guess I could have the newly created friend call a method called UpdateFormControls (that updates every control on the form whether its needed or not) but that seems like a not-too-good way to do the updating. =================================== This list is hosted by DevelopMentor. http://www.develop.com View archives and manage your subscription(s) at http://discuss.develop.com =================================== This list is hosted by DevelopMentorĀ® http://www.develop.com View archives and manage your subscription(s) at http://discuss.develop.com