'cross-thread operation not valid' exception / multithreaded compo

G

Guest

Hello,

There are several 'cross-thread operation not valid' exception postings in
the MSDN discussion groups, but none address my exact situation.

I have authored a .NET component in Visual C# .NET 2003 that is capable of
firing several types of events to notify user of errors, data changes, etc.
The component uses a thread to perform background communications and if there
is an error or data-change fires an event to notify the user. If the
developer that is using my component wishes to display the value form
control's Text property, the 'cross-thread operation not valid' exception is
thrown in VS.NET 2005.

I understand why it is thrown (worker thread not allowed to update UI
thread), but can't find any definitive information on whether this is
addressable from the component standpoint, rather than requiring my
component's user to use delegates and IsInvokeRequired/Invoke to display the
values.

Any feedback or suggestions would be appreciated.
 
K

Kevin Spencer

No, it's not necessary to require the user of the component to use
delegates, or any of that stuff. It is entirely possible to hide the
threading from the user, and the form in which the component is hosted.
Remember that the component itself resides in the same thread as the form.
It is the thread spawned by the component which is in another thread. As
long as your component itself manages the marshalling internally and fires
the event in the form's thread, it should not be a problem.

--
HTH,

Kevin Spencer
Microsoft MVP
Professional Numbskull

Show me your certification without works,
and I'll show my certification
*by* my works.
 
P

Peter Huang [MSFT]

Dear Customer,

In addition to Kevin's suggestion, I think you may try to take a look at
the three articles below about how to update UI from another thread for
your reference.

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

As almost every winform related class is not thread-safe, we have to
marshal all the call on the winform thread.
The .Net provides a simple method, Control.Invoke will marshal the call
onto the thread where the Control is. Also we can use SendMessage to
marshal the call, which is what the Control.Invoke do.

Best regards,

Peter Huang

Microsoft Online Community Support
==================================================
When responding to posts, please "Reply to Group" via your newsreader so
that others may learn and benefit from your issue.
==================================================
This posting is provided "AS IS" with no warranties, and confers no rights.
 
G

Guest

Hi Peter,

As a component, I don't have access to the target UI control and do not know
what type of control will be updated from the event sink.

The articles that you suggested all describe a monolithic application where
a thread is started in a Win Forms application, and the event sink has
knowledge of the type of Win form control that will be updated.

I started down the path that Kevin described, but I'm having trouble
figuring out how to notify my component from the worker thread that an event
needs to be fired. I've tried setting up a delegate and using BeginInvoke,
but the same exception is thrown.
Also we can use SendMessage to marshal the call, which is what the Control.Invoke do.

Can you elaborate on SendMessage usage in .NET?
 
G

Guest

Hi Kevin,

I started down the path that you described, but I'm having trouble figuring
out how to notify my component from the worker thread that an event needs to
be fired on the UI thread. I've tried setting up a delegate and using
BeginInvoke, but the same exception is thrown (presumably because
BeginInvoke creates a thread to perform its work).

Any suggestions on how to make the 'component manage the marshalling
internally'?

Thanks in advance.
 
J

Jon Skeet [C# MVP]

HairlipDog58 said:
As a component, I don't have access to the target UI control and do not know
what type of control will be updated from the event sink.

The articles that you suggested all describe a monolithic application where
a thread is started in a Win Forms application, and the event sink has
knowledge of the type of Win form control that will be updated.

Well, *something* certainly needs to know what will be updated.
However, UI components can expose thread-safe methods which perform the
necessary marshalling to the UI thread themselves. They would naturally
know which UI control to do things with.
I started down the path that Kevin described, but I'm having trouble
figuring out how to notify my component from the worker thread that an event
needs to be fired. I've tried setting up a delegate and using BeginInvoke,
but the same exception is thrown.

Could you post a short but complete program which demonstrates the
problem?

See http://www.pobox.com/~skeet/csharp/complete.html for details of
what I mean by that.
 
K

Kevin Spencer

There's a really good series on this topic on the MSDN online library:

http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnforms/html/winforms06112002.asp
http://msdn.microsoft.com/library/en-us/dnforms/html/winforms08162002.asp?frame=true
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnforms/html/winforms08162002.asp

In addition, if you're working with .Net platform 2.0, you might want to
have a look at the System.ComponentModel.BackgroundWorker class:

http://msdn2.microsoft.com/en-US/library/system.componentmodel.backgroundworker.aspx

--
HTH,

Kevin Spencer
Microsoft MVP
Professional Numbskull

Show me your certification without works,
and I'll show my certification
*by* my works.
 
G

Guest

Hi Peter,

I re-phrased this in attempt to clarify the situation:

F = Form class
C = Component class
T = Thread

1. C is a component used by F.
2. C has an event called MyEvent and property called MyInteger.
3. T is a worker thread started by C.
4. T performs interval-based work then needs to notify C that the work has
been performed.
5. C must then fire MyEvent to notify F that work has been completed.
6. F has an OnMyEvent handler that that needs to update a UI control with
the data contained in MyInteger.

The cross-thread exception occurs because T is a different thread than C
(which is in the same thread as F). So T cannot call a method on C that
causes an event to fire.

The question is, how can T notify C that it has completed its work, so that
C can fire an event to notify F that new data is available?

I've tried using a delegate and BeginInvoke with same problem results (I'm
guessing BeginInvoke also causes a thread to be created).

I have a small example project that demonstrates the problem, but it is too
big to post here.
 
P

Peter Huang [MSFT]

Hi,

Thanks for your update.
So far one approach is as Kevin suggested, we can try to use
BackgroundWorker.

As you said, the component as a different control, it did not implement
ISynchronizeInvoke, which did not support to marshal call across thread.
As I said before the Control.Invoke implement call across thread via
SendMessage which worked with Windows.

For Component that did not have window, it did not work.

So for your scenario, I think you may try redesign your component to have a
window.
1. Create a hidden windows form, so that we can call invoke on that form's
instance.
2. Try to pass the outside form into the component.


Best regards,

Peter Huang

Microsoft Online Community Support
==================================================
When responding to posts, please "Reply to Group" via your newsreader so
that others may learn and benefit from your issue.
==================================================
This posting is provided "AS IS" with no warranties, and confers no rights.
 
G

Guest

I did some simple tests and determined that BackgroundWorker solves the
problem when the component is used in Win Forms apps but doesn't work in
console/service apps. The thread works but notifications don't (no message
pump), so console/service apps need special handling.

Is there a way to determine whether the component is being used in a Win
Forms or console/service app?
 
P

Peter Huang [MSFT]

Hi

BackgroundWorker is mainly used in a Winform application which have an
messasge bump.
For a windowless application(Console/Service), I think you may try to use
other mechanism.
e.g.
AutoResetEvent Class

In the Main thread, a while statement will query for the event to if it is
signaled.
AutoResetEvent Class
http://msdn2.microsoft.com/en-us/library/system.threading.autoresetevent.asp
x

Best regards,

Peter Huang

Microsoft Online Community Support
==================================================
When responding to posts, please "Reply to Group" via your newsreader so
that others may learn and benefit from your issue.
==================================================
This posting is provided "AS IS" with no warranties, and confers no rights.
 
P

Peter Huang [MSFT]

Dear Customer,

Just want to say Hi, and I was wondering how everything is going.
If anything is unclear, please let me know.
It is my pleasure to be of assistance.


Best regards,

Peter Huang

Microsoft Online Community Support
==================================================
When responding to posts, please "Reply to Group" via your newsreader so
that others may learn and benefit from your issue.
==================================================
This posting is provided "AS IS" with no warranties, and confers no rights.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top