Can I create a thread safe Winform User Control

E

Ethan Strauss

Hi,
I know that if I want to update a Windows Form Control from a worker
thread I need to check InvokeRequired on the control and jump through some
hoops. I can get that all to work. But, I wonder if I can make a User Control
which inherits from for example, System.Windows.Forms.Label, and has the
correct thread safe set method built in? In fact, why are Windows Forms
controls not thread safe? It seems like it would have been pretty easy to
build in, at least for the their simple properties, and would save a fair
amount of fiddly work on the developer's part.

Thanks,
Ethan
 
P

Peter Duniho

Ethan said:
Hi,
I know that if I want to update a Windows Form Control from a worker
thread I need to check InvokeRequired on the control and jump through some
hoops. I can get that all to work. But, I wonder if I can make a User Control
which inherits from for example, System.Windows.Forms.Label, and has the
correct thread safe set method built in?

No, you can't, not really. At best, you could hide the existing public
methods with a wrapper that does the necessary work, or implement a
whole new separate API, but it would always be possible to call the
un-wrapped methods in code that isn't aware of your specific subclass type.
In fact, why are Windows Forms
controls not thread safe? It seems like it would have been pretty easy to
build in, at least for the their simple properties, and would save a fair
amount of fiddly work on the developer's part.

I've wondered the same thing, and don't have a specific answer. But I
suspect it's related to the fact that a) there's a certain amount of
performance overhead that would be incurred in _all_ scenarios,
including the 95% case of not needing multi-threading support, b) doing
the cross-thread invocation implicitly introduces the possibility of
deadlock to a developer who may not know much or anything about
threading bugs, and c) making the cross-thread invocation an explicit
implementation detail allows for the client code to determine on a
case-by-case basis whether to use synchronous invocation (Invoke()) or
asynchronous invocation (BeginInvoke()).

There may yet be other reasons I haven't considered.

Pete
 
E

Ethan Strauss

Thanks Pete,
It still seems odd that they couldn't build it in. It could be a
ThreadSafeSetText() type method and still leave the standard methods and
properties in place. Oh well. It's not that hard to do my own.
A strange thing I just noticed is that, using vsto, the controls in the
ribbon (Microsoft.Office.Tools.Ribbon.RibbonControl) don't have an
InvokeRequired property. I wonder if they are already thread safe? I found
this statement "Any public static (Shared in Visual Basic) members of this
type are thread safe. Any instance members are not guaranteed to be thread
safe. " about ribbon controls, but I am not sure what is meant by "public
static members" and "instance members". That's from
http://msdn.microsoft.com/en-us/library/microsoft.office.tools.ribbon.ribboncontrol.aspx
Ethan
 
P

Peter Duniho

Ethan said:
[...]
A strange thing I just noticed is that, using vsto, the controls in the
ribbon (Microsoft.Office.Tools.Ribbon.RibbonControl) don't have an
InvokeRequired property. I wonder if they are already thread safe?

Careful. There's a difference between the thread affinity that involves
InvokeRequired and thread safety. For example, even if you synchronized
all access to your System.Windows.Forms.Control sub-classes so that an
instance was ever only accessed on one thread at a time, you would
_still_ have the requirement that the non-client class members (i.e.
those not added by you in a sub-class) be accessed only on the thread
that owns the instance.

Conversely, just because some other type of GUI control doesn't inherit
from the System.Windows.Forms.Control class, nor have an InvokeRequired
property, that doesn't mean that the type is thread-SAFE. It just
(probably) means that the control doesn't have the same thread affinity
issue that the System.Windows.Forms.Control sub-classes do.

(I say probably because the control you're asking about is part of the
Office interop types, which I'm not that familiar with. I don't know
for sure that it doesn't have a thread affinity issue).
I found
this statement "Any public static (Shared in Visual Basic) members of this
type are thread safe. Any instance members are not guaranteed to be thread
safe. " about ribbon controls, but I am not sure what is meant by "public
static members" and "instance members". That's from
http://msdn.microsoft.com/en-us/library/microsoft.office.tools.ribbon.ribboncontrol.aspx

That language is Microsoft's standard boilerplate language for .NET
types. Again, it doesn't relate to thread affinity, but rather to
thread safety, which is not quite the same thing.

In particular, in that type (and others with the same comment, which is
something like 90% or more of .NET) your code can safely access static
members of the type without synchronization between threads. But for a
given instance, your own code is required to handle synchronization if
more than one thread is accessing members _of that instance_ at the same
time.

Note that individual instances are independent of each other. You can
access instance members of one instance in one thread and instance
members of a different instance in another thread without needing to
synchronize the two threads.

Note also that for controls that _do_ have thread affinity, the thread
safety issue tends to be moot, because your code is always only ever
accessing instances of controls like that on the thread that owns the
control. The control is, in addition to having thread affinity, also
_not_ thread safe for instance members, but because you can't even
access the members of the class except on the owning thread, the lack of
thread safety isn't an issue (*).

Pete

(*) (unless, of course, you are dealing with your own sub-class and
members that you know to not have thread affinity issues...then you do
have to deal with the lack of thread-safety if you choose to access
those client-declared members in multiple threads simultaneously).
 
E

Ethan Strauss

Thanks Pete,
That was quite helpful. I didn't even know thread affinity existed!
Ethan

Peter Duniho said:
Ethan said:
[...]
A strange thing I just noticed is that, using vsto, the controls in the
ribbon (Microsoft.Office.Tools.Ribbon.RibbonControl) don't have an
InvokeRequired property. I wonder if they are already thread safe?

Careful. There's a difference between the thread affinity that involves
InvokeRequired and thread safety. For example, even if you synchronized
all access to your System.Windows.Forms.Control sub-classes so that an
instance was ever only accessed on one thread at a time, you would
_still_ have the requirement that the non-client class members (i.e.
those not added by you in a sub-class) be accessed only on the thread
that owns the instance.

Conversely, just because some other type of GUI control doesn't inherit
from the System.Windows.Forms.Control class, nor have an InvokeRequired
property, that doesn't mean that the type is thread-SAFE. It just
(probably) means that the control doesn't have the same thread affinity
issue that the System.Windows.Forms.Control sub-classes do.

(I say probably because the control you're asking about is part of the
Office interop types, which I'm not that familiar with. I don't know
for sure that it doesn't have a thread affinity issue).
I found
this statement "Any public static (Shared in Visual Basic) members of this
type are thread safe. Any instance members are not guaranteed to be thread
safe. " about ribbon controls, but I am not sure what is meant by "public
static members" and "instance members". That's from
http://msdn.microsoft.com/en-us/library/microsoft.office.tools.ribbon.ribboncontrol.aspx

That language is Microsoft's standard boilerplate language for .NET
types. Again, it doesn't relate to thread affinity, but rather to
thread safety, which is not quite the same thing.

In particular, in that type (and others with the same comment, which is
something like 90% or more of .NET) your code can safely access static
members of the type without synchronization between threads. But for a
given instance, your own code is required to handle synchronization if
more than one thread is accessing members _of that instance_ at the same
time.

Note that individual instances are independent of each other. You can
access instance members of one instance in one thread and instance
members of a different instance in another thread without needing to
synchronize the two threads.

Note also that for controls that _do_ have thread affinity, the thread
safety issue tends to be moot, because your code is always only ever
accessing instances of controls like that on the thread that owns the
control. The control is, in addition to having thread affinity, also
_not_ thread safe for instance members, but because you can't even
access the members of the class except on the owning thread, the lack of
thread safety isn't an issue (*).

Pete

(*) (unless, of course, you are dealing with your own sub-class and
members that you know to not have thread affinity issues...then you do
have to deal with the lack of thread-safety if you choose to access
those client-declared members in multiple threads simultaneously).
.
 

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