|
dev
newsgroups
|
|||||||||||||||||||||||
|
|||||||||||||||||||||||
Multithreading problem in Windows Form appI have a tough problem in a Windows Form app. It uses the background worker object to do some, well, background work. I need this because I want this worker to be feeding a listbox logging its progress. I am using the correct protocol to deal with interthread call from the worker to the listbox, ie.: -------- private void AddLineOfInfo( string info ) { this.txtProgress.Text += info; } private delegate void ClearInfo(); private void AddThisInfo( string info ) { Invoke( new SetInfo( this.AddLineOfInfo), new object[] { info } ); } ----------------- So I only directly call AddThisInfo. This seems to work fine. However, I need to access this method from an object created in the background worker thread. So I thought I would pass 'this' as a parameter to this new object's constructor. 'this' is a form...and I think the problem starts here! When I invokee the constructor of this new object passing 'this', the debugger becomes sort of frozen for a bit and then finally when it allows me to Break All, the worker thread seems blocked -- no action whatsoever. All in all, the app freezes and I am forced to Stop Debugging. My theory is that one thread is having difficulty accessing the form on the other thread. The exact explanation is what I lack!! Any insight? -- Thanks in advance, Juan Dent, M.Sc. Hi Juan,
From you description, I understand that you want to implement multithreading in Windows Forms. If I misunderstood, please feel free to let me know. Almost all the UI controls are not thread safe, including the Form class. From the MSDN, we know that a non-static form object is not thread safe. We can not access an object which is not thread safe from other threads other than the thread that creates the object. This may cause unexpected behavior. "Thread Safety Any public static (Shared in Visual Basic) members of this type are thread safe. Any instance members are not guaranteed to be thread safe." Here are some links about how to implement multithreading in Windows Forms. Safe, Simple Multithreading in Windows Forms, Part 1 http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnforms/htm l/winforms06112002.asp Safe, Simple Multithreading in Windows Forms, Part 2 http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnforms/htm l/winforms08162002.asp Safe, Simple Multithreading in Windows Forms, Part 3 http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnforms/htm l/winforms01232003.asp If you still have any concern, please feel free to let me know. I look forward to hearing from you. Best regards, Peter Huang Microsoft Online Partner Support Get Secure! - www.microsoft.com/security This posting is provided "AS IS" with no warranties, and confers no rights. As Peter Huang pointed out access to windows controls (including their
properties) is not thread safe. This is rooted from deep within Windows, it's not something new to .NET development. The gist of content of his references is that you must force the thread that created the control to perform the operation. This is done via a delegate and a call to Invoke or BeginInvoke. This can be generalized further by testing InvokeRequired. In your example you could make your AddLineOfInfo method thread safe as follows: private delegate void AddLineOfInfoDelegate(string info); private void AddLineOfInfo(string info) { if(InvokeRequired) { Invoke(new AddLineOfInfoDelegate(AddLineOfInfo), new object[] {info}); } else { txtProgress.Text += info; } } With other methods, depending on the method, you may not need to declare your own delegate. For example, if you had a method with a object and an EventArgs private void MyMethod(object sender, EventArgs e) { if(InvokeRequired) { Invoke(new EventHandler(MyMethod), new object[] {sender, e}); } else { txtProgress.Text += info; } } Many of the Forms multit-hreading examples show assigning the new delegate to a variable before invocation (from .NET Framework Developer's Guide - Multithreaded Windows Forms Control Sample): private EventHandler onSearchComplete; //... onSearchComplete = new EventHandler(OnSearchComplete); //... BeginInvoke(onSearchComplete, new object[] {this, EventArgs.Empty}); With low-frenquency methods I prefer not to pollute the class with variables when they don't really add value. In Visual Studio 2005 (.NET 2.0) you will actually get exceptions with some of the debugging helpers when you perform thread unsafe access to forms and their properties, which is a little more helpful then a hang or a crash. Show quote "Juan Dent" wrote: > Hi, > > I have a tough problem in a Windows Form app. It uses the background worker > object to do some, well, background work. I need this because I want this > worker to be feeding a listbox logging its progress. I am using the correct > protocol to deal with interthread call from the worker to the listbox, ie.: > > -------- > private void AddLineOfInfo( string info ) > { > this.txtProgress.Text += info; > } > private delegate void ClearInfo(); > private void AddThisInfo( string info ) > { > Invoke( new SetInfo( this.AddLineOfInfo), new object[] { info } ); > } > ----------------- > > So I only directly call AddThisInfo. This seems to work fine. However, I > need to access this method from an object created in the background worker > thread. So I thought I would pass 'this' as a parameter to this new object's > constructor. 'this' is a form...and I think the problem starts here! > > When I invokee the constructor of this new object passing 'this', the > debugger becomes sort of frozen for a bit and then finally when it allows me > to Break All, the worker thread seems blocked -- no action whatsoever. > > All in all, the app freezes and I am forced to Stop Debugging. > > > My theory is that one thread is having difficulty accessing the form on the > other thread. The exact explanation is what I lack!! |
|||||||||||||||||||||||