Please don't misinterpret this as lack of gratitude for your time, but
none of your response helped considering I spelled out the issues in
the OP. Maybe the following clarifications will help.
"Tom Shelton" wrote:
>First off, this/me has nothing at all to do with windows forms. It is
a reference to the current object instance. So, it is valid inside of
a service class - it's valid inside any class (well any instance
method anyway, it isn't valid inside of shared methods since there is
no instance to refer to).
That's all correct.
>In other words, it is perfectly valid to
pass a me reference inside of a windows service to Monitor.TryEnter.
It's valid, but it doesn't work, that's why I'm here. Just to
clarify, my class is instantiated from a service or other container,
and my class encapsulates the Timer - the service does not instantiate
the timer, so this/me for the service isn't in the scope of the timer
unless I pass it in (which may be necessary the way this is going).
Almost all examples use a timer within Windows Forms where this/me
refers to a Windows Forms object which can be used as a
SynchronizingObject. Here is the text from MSDN and it seems everyone
references this text:
When the Elapsed event is handled by a visual Windows Forms
component, such as a button, accessing the component through the
system-thread pool might result in an exception or just might not
work. Avoid this effect by setting SynchronizingObject to a Windows
Forms component, which causes the method that handles the Elapsed
event to be called on the same thread that the component was created
on.
It seems so many people who describe timers fall back on this example
that it's become impossible for me to find an example that doesn't use
a Windows Forms component for synchronization. Well, when we're not
running a GUI we don't have a Windows Forms component to use, unless
we just instantiate one just for the purpose, which seems silly. What
I'm finding is that this/me does no good unless we sync on such a
component. I even created my own implementation of ISynchronizeInvoke
and instantiated an object from there to sync on - all events get
marshalled through my proxy but everything I use in
Monitor.TryEnter(whatever) still fails.
As another example, here's another hint at the problem from a blog,
one of many where this sort of issue is mentioned:
The server-based timer is designed for use with worker threads
in a multithreaded environment. Server timers can move among threads
to handle the raised Elapsed event, resulting in more accuracy
(metronome-quality) than Windows timers. The System.Timers.Timer class
will call the timer event handler on a worker thread obtained from the
common language runtime (CLR) thread pool. When using the
System.Timers.Timer, be sure to set the appropriate Principal to the
thread that will execute the Elapsed event because this worker thread
won't inherit the Principal from the main thread.
I'm trying to do what's stated there, by trying to find some reference
type that can be used as a sync object, the above mentioned
"Principal". But it seems no matter what I use there are worker
threads being used that are not using true references back to the main
instance. So my Monitor.Enter(whatever) is failing because "whatever"
is different on some of the threads spawned in the threadpool.
>You should keep in mind that you want to keep locks as small as
possible since they can impact performance. You only need a lock when
accessing shared resources, such as instance variables inside a class -
and then only if the access is read-write.
Full agreement. The application code does a lot of things including
communications, handling of single-threaded events from encapsulated
objects, etc - I need to synchronize timer events or all of this falls
apart with threads resetting status values at the wrong time. This
isn't supposed to be a multi-threaded app, but the behaviour of the
Timer is forcing me to recode it like it is.
>Generally, you don't want
to make the lock object shared (unless the resource being protected is
shared) - because that will cause you to lock every instance of the
class and that is generally not what you want, since usually the
resource that you are protecting is local to that instance.
In this case it Is what I want. I want a timer that will tick off
time. Understanding it may tick while I'm still doing something, I
want to throw away the events that I don't need. If Monitor.TryEnter
fails then I can throw away the tick. Unfortunately, while you're
saying "that will cause you to lock every instance of the class", I
only have one class instance and some of the events (not all!) are
still getting through the TryEnter.
>As for the question about what is appropriate to pass to the various
Monitor methods - well, any reference type will do.
That simply isn't correct. "Any reference type will do" isn't
working, which is what I stated in the OP. As indicated above, I've
instantiated a number of different kinds of reference types, not
structures, that still don't lock out all events. It seems evident
that System.Windows.Forms.Form objects have something that is needed
here that I haven't figured out yet. I haven't yet tried to create a
dummy class that derives from Forms.Control which has an hWnd property
- maybe that's what this thing needs, that's what the trick was before
..NET. As I said above, I think that's silly.
>Don't use anything
that is a structure - it must be a reference type.
Agreed.
Thanks again for your time.