|
web
newsgroups
|
|||||||||||||||||||||||
|
|||||||||||||||||||||||
System.Timers.Timer, thread synchronization issuesdifferent intervals. My class can be instantiated within a Windows Form or from a Windows Service. Actions performed by one of the event handlers may take longer than the interval for either of the timers, so it's possible for multiple events to fire "simultaneously" and for events to queue up. I'm attempting to get the timers to sync on some reference type object, or use System.Threading.Monitor to stop them from re-entering code that's already being executed. When a timer event fires I use Monitor.TryEnter(refobj) to attempt a lock, and simply return on failure (in other words, don't bother trying to do anything, we're already doing something). The refobj is an instance of another one of my classes, but this doesn't appear to be a suitable sync object. I've tried making the object static/shared so the same object is consistent across threads. Using this/me doesn't work. I can't use a this/me reference to a Windows Form because the code could be instantiated from a Service. I am using similar code on methods invoked from the container - if a timer event is doing some operation within the instance, the container is informed that the object is busy, rather than making it wait for a turn. If I can't lockdown the object then timers and user requests are in contention, and the rest of the code outside of these entry points is not thread-safe. What type of object do I use to ensure Monitor.Enter(object) and related methods will be respected by any thread? All of the classic examples on the Net assume we can use 'this' or 'Me' and that we're running in a Windows Form. This isn't valid for Windows Services, especially when events like OnPause and OnContinue may get run from a different thread than the one that started the process. Thanks! Tony Gravagno wrote:
Show quoteHide quote > I have a class that instantiates two Timer objects that fire at First off, this/me has nothing at all to do with windows forms. It is> different intervals. My class can be instantiated within a Windows > Form or from a Windows Service. Actions performed by one of the event > handlers may take longer than the interval for either of the timers, > so it's possible for multiple events to fire "simultaneously" and for > events to queue up. I'm attempting to get the timers to sync on some > reference type object, or use System.Threading.Monitor to stop them > from re-entering code that's already being executed. > > When a timer event fires I use Monitor.TryEnter(refobj) to attempt a > lock, and simply return on failure (in other words, don't bother > trying to do anything, we're already doing something). The refobj is > an instance of another one of my classes, but this doesn't appear to > be a suitable sync object. > > I've tried making the object static/shared so the same object is > consistent across threads. Using this/me doesn't work. I can't use a > this/me reference to a Windows Form because the code could be > instantiated from a Service. > > I am using similar code on methods invoked from the container - if a > timer event is doing some operation within the instance, the container > is informed that the object is busy, rather than making it wait for a > turn. If I can't lockdown the object then timers and user requests > are in contention, and the rest of the code outside of these entry > points is not thread-safe. > > What type of object do I use to ensure Monitor.Enter(object) and > related methods will be respected by any thread? All of the classic > examples on the Net assume we can use 'this' or 'Me' and that we're > running in a Windows Form. This isn't valid for Windows Services, > especially when events like OnPause and OnContinue may get run from a > different thread than the one that started the process. > > Thanks! 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). In other words, it is perfectly valid to pass a me reference inside of a windows service to Monitor.TryEnter. 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. 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. As for the question about what is appropriate to pass to the various Monitor methods - well, any reference type will do. Don't use anything that is a structure - it must be a reference type. -- Tom Shelton 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: That's all correct.>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). >In other words, it is perfectly valid to It's valid, but it doesn't work, that's why I'm here. Just to>pass a me reference inside of a windows service to Monitor.TryEnter. 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 Full agreement. The application code does a lot of things including>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. 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 In this case it Is what I want. I want a timer that will tick off>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. 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 That simply isn't correct. "Any reference type will do" isn't>Monitor methods - well, any reference type will do. 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 Agreed.>that is a structure - it must be a reference type. Thanks again for your time. Actually, a lot of people advise *not* locking on "me"/"this", because it
allows external callers to lock on the object, causing possible deadlock scenarios that were not anticipated. *ANY* reference type can be used as a lock object. As long as each thread has access to the same reference (and you don't keep changing that reference), then it will lock correctly. Depending on the scenario, you might want to use a static lock object (i.e. "private readonly object SyncLock = new object();", or you might want to pass a lock object to your thread when spawning it. If you can't (for whatever reason) pass the sync-lock (or an encapsulating class) around, then another solution is to use a named Mutex or similar. Marc Tony Gravagno wrote:
Show quoteHide quote > I have a class that instantiates two Timer objects that fire at First off, this/me has nothing at all to do with windows forms. It is> different intervals. My class can be instantiated within a Windows > Form or from a Windows Service. Actions performed by one of the event > handlers may take longer than the interval for either of the timers, > so it's possible for multiple events to fire "simultaneously" and for > events to queue up. I'm attempting to get the timers to sync on some > reference type object, or use System.Threading.Monitor to stop them > from re-entering code that's already being executed. > > When a timer event fires I use Monitor.TryEnter(refobj) to attempt a > lock, and simply return on failure (in other words, don't bother > trying to do anything, we're already doing something). The refobj is > an instance of another one of my classes, but this doesn't appear to > be a suitable sync object. > > I've tried making the object static/shared so the same object is > consistent across threads. Using this/me doesn't work. I can't use a > this/me reference to a Windows Form because the code could be > instantiated from a Service. > > I am using similar code on methods invoked from the container - if a > timer event is doing some operation within the instance, the container > is informed that the object is busy, rather than making it wait for a > turn. If I can't lockdown the object then timers and user requests > are in contention, and the rest of the code outside of these entry > points is not thread-safe. > > What type of object do I use to ensure Monitor.Enter(object) and > related methods will be respected by any thread? All of the classic > examples on the Net assume we can use 'this' or 'Me' and that we're > running in a Windows Form. This isn't valid for Windows Services, > especially when events like OnPause and OnContinue may get run from a > different thread than the one that started the process. > > Thanks! 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). In other words, it is perfectly valid to pass a me reference inside of a windows service to Monitor.TryEnter. 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. 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. As for the question about what is appropriate to pass to the various Monitor methods - well, any reference type will do. Don't use anything that is a structure - it must be a reference type. -- Tom Shelton 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: That's all correct.>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). >In other words, it is perfectly valid to It's valid, but it doesn't work, that's why I'm here. Just to>pass a me reference inside of a windows service to Monitor.TryEnter. 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 Full agreement. The application code does a lot of things including>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. 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 In this case it Is what I want. I want a timer that will tick off>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. 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 That simply isn't correct. "Any reference type will do" isn't>Monitor methods - well, any reference type will do. 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 Agreed.>that is a structure - it must be a reference type. Thanks again for your time. oops - missed the key keyword... just imagine the "static" was there all
along... Marc Actually, a lot of people advise *not* locking on "me"/"this", because it
allows external callers to lock on the object, causing possible deadlock scenarios that were not anticipated. *ANY* reference type can be used as a lock object. As long as each thread has access to the same reference (and you don't keep changing that reference), then it will lock correctly. Depending on the scenario, you might want to use a static lock object (i.e. "private readonly object SyncLock = new object();", or you might want to pass a lock object to your thread when spawning it. If you can't (for whatever reason) pass the sync-lock (or an encapsulating class) around, then another solution is to use a named Mutex or similar. Marc oops - missed the key keyword... just imagine the "static" was there all
along... Marc Problem solved: The VS2005 debugger has a tendency to skip breakpoints
when events queue up. When one-stepping through code, we can expect control will jump to the event handler on events, but then we'll usually see it go back to where we originally were - in a multi-threaded app we're used to this. What I was seeing was that control would jump to the event handler and stay there, and then one-stepping would continue into the Monitor block which I thought was failing. What's really happening is that even if you're using the F11 one-step, all code between the current line and the event handler will get executed without the debugger walking through it. More break points might have shown this earlier. Is that a bug or a feature? Any setting to ensure that "Step Into" works through ALL code? I proved that the sync-lock was working by putting an always incrementing counter at the beginning of my event handler. Then I put another counter that incremented once past the Monitor.TryEnter and decremented on the Monitor.Exit. I have a test to see if that second counter is ever greater than one and it was not. The first counter seemed to increment properly whether I saw the event or not. Yes, "this/me" will work. Sorry for the confusion. I've posted snips of my code below for anyone else who needs to implement something like this. HTH Thanks again. Show quoteHide quote "Marc Gravell" wrote: The object assigned to System.Timers.Timer.SynchronizingObject must>Actually, a lot of people advise *not* locking on "me"/"this", because it >allows external callers to lock on the object, causing possible deadlock >scenarios that were not anticipated. > >*ANY* reference type can be used as a lock object. As long as each thread >has access to the same reference (and you don't keep changing that >reference), then it will lock correctly. Depending on the scenario, you >might want to use a static lock object (i.e. "private readonly object >SyncLock = new object();", or you might want to pass a lock object to your >thread when spawning it. > >If you can't (for whatever reason) pass the sync-lock (or an encapsulating >class) around, then another solution is to use a named Mutex or similar. > >Marc > >oops - missed the key keyword... just imagine the "static" >was there all along... implement ISynchronizeInvoke, so you can't just sync the timer itself on anything. Not knowing any class that implements this I created my own, and while it does marshal requests it wasn't necessary for this. Here is some skeleton code in C# but the same base should work with VB. class MyClass() { private SyncronizationObject SyncObject = new SyncronizationObject(); // that's my implementation of ISynchronizationObject private static Object SyncLock = new Object(); private static int concurrent = 0; // testing only private static int events = 0; // testing only ... } void Init() { tTimer = new System.Timers.Timer(); tTimer.SynchronizingObject = SyncObject; // That's only a proxy between the event and the handler, // it can be removed. tTimer.Elapsed += new System.Timers.ElapsedEventHandler(tTimer_Elapsed); tTimer.Interval = 5000; tTimer.AutoReset = true; tTimer.Enabled = true; } void tTimer_Elapsed( object sender, System.Timers.ElapsedEventArgs e) { events += 1; if (!Monitor.TryEnter(SyncLock)) { return; } try { concurrent += 1; if (concurrent > 1) { throw new Exception("Concurrency issue1"); // this event was never thrown, // proof that locking was working } HandleTransaction(); } finally { concurrent -= 1; if (concurrent > 1) { throw new Exception("Concurrency issue2"); } Monitor.Exit(SyncLock); } } The first time the event fires, TryEnter is true and allows execution of the following code block. The next few times the event fires, the TryEnter fails as it should. After a while, as I'm walking through code in debug in VS2005, it looks like events start coming through the TryEnter like a freight train. What's happening is that VS2005 just doesn't show all of the code being handled in method HandleTransaction, so it just looks like that code is being handled in different threads. Problem solved: The VS2005 debugger has a tendency to skip breakpoints
when events queue up. When one-stepping through code, we can expect control will jump to the event handler on events, but then we'll usually see it go back to where we originally were - in a multi-threaded app we're used to this. What I was seeing was that control would jump to the event handler and stay there, and then one-stepping would continue into the Monitor block which I thought was failing. What's really happening is that even if you're using the F11 one-step, all code between the current line and the event handler will get executed without the debugger walking through it. More break points might have shown this earlier. Is that a bug or a feature? Any setting to ensure that "Step Into" works through ALL code? I proved that the sync-lock was working by putting an always incrementing counter at the beginning of my event handler. Then I put another counter that incremented once past the Monitor.TryEnter and decremented on the Monitor.Exit. I have a test to see if that second counter is ever greater than one and it was not. The first counter seemed to increment properly whether I saw the event or not. Yes, "this/me" will work. Sorry for the confusion. I've posted snips of my code below for anyone else who needs to implement something like this. HTH Thanks again. Show quoteHide quote "Marc Gravell" wrote: The object assigned to System.Timers.Timer.SynchronizingObject must>Actually, a lot of people advise *not* locking on "me"/"this", because it >allows external callers to lock on the object, causing possible deadlock >scenarios that were not anticipated. > >*ANY* reference type can be used as a lock object. As long as each thread >has access to the same reference (and you don't keep changing that >reference), then it will lock correctly. Depending on the scenario, you >might want to use a static lock object (i.e. "private readonly object >SyncLock = new object();", or you might want to pass a lock object to your >thread when spawning it. > >If you can't (for whatever reason) pass the sync-lock (or an encapsulating >class) around, then another solution is to use a named Mutex or similar. > >Marc > >oops - missed the key keyword... just imagine the "static" >was there all along... implement ISynchronizeInvoke, so you can't just sync the timer itself on anything. Not knowing any class that implements this I created my own, and while it does marshal requests it wasn't necessary for this. Here is some skeleton code in C# but the same base should work with VB. class MyClass() { private SyncronizationObject SyncObject = new SyncronizationObject(); // that's my implementation of ISynchronizationObject private static Object SyncLock = new Object(); private static int concurrent = 0; // testing only private static int events = 0; // testing only ... } void Init() { tTimer = new System.Timers.Timer(); tTimer.SynchronizingObject = SyncObject; // That's only a proxy between the event and the handler, // it can be removed. tTimer.Elapsed += new System.Timers.ElapsedEventHandler(tTimer_Elapsed); tTimer.Interval = 5000; tTimer.AutoReset = true; tTimer.Enabled = true; } void tTimer_Elapsed( object sender, System.Timers.ElapsedEventArgs e) { events += 1; if (!Monitor.TryEnter(SyncLock)) { return; } try { concurrent += 1; if (concurrent > 1) { throw new Exception("Concurrency issue1"); // this event was never thrown, // proof that locking was working } HandleTransaction(); } finally { concurrent -= 1; if (concurrent > 1) { throw new Exception("Concurrency issue2"); } Monitor.Exit(SyncLock); } } The first time the event fires, TryEnter is true and allows execution of the following code block. The next few times the event fires, the TryEnter fails as it should. After a while, as I'm walking through code in debug in VS2005, it looks like events start coming through the TryEnter like a freight train. What's happening is that VS2005 just doesn't show all of the code being handled in method HandleTransaction, so it just looks like that code is being handled in different threads.
Thread.Sleep slowing down the whole application
Play wavs in VB2005. Compression namespace for Array DataGridViewCell has lost its DataGridView - How to solve? Creating an array of textbox objects Able .NET ? GUIDS not creating correctly in vb.net Can I add them to the context menu and programmically copy them to the main menu Getting IE Page Contents using ENTER key to move to the right cell datagridview |
|||||||||||||||||||||||