Monitor.TryEnter with a common class

I have a situation where for testing, I want my timer method (FooMethod) to run one at a time. In the example below, FooMethod is passed as a delegate to a timer. There are many specific examples of this class. I thought that by setting _locker static, only one instance of FooMethod () would process at a time. But when I run the application, several threads go through the TryEnter () line at a time.

This is how I add each class to the new timer. This is done in a loop for each instance of foo:

_timers.Add(new Timer(foo.FooMethod, null, 0, 10000)); 

And this is the class that has this method:

 public class Foo<T> { private static readonly object _locker = new object(); public void FooMethod(object stateInfo) { // Don't let threads back up; just get out if (!Monitor.TryEnter(_locker)) { return; } try { // Logic here } finally { Monitor.Exit(_locker); } } } 

Note. As a rule, _locker is not static; I do not want the same thread to introduce a method before it gets a chance to complete. I changed it to statics here for testing.

My first thought is that maybe this is not working because the class is generic? And that each particular class is actually its own class, and they do not share the _locker variable? It's true? If this is true, how should I have specific classes sharing the _locker variable? Do I need to add the _locker static variable to some other class that Foos have access to?

+7
source share
4 answers

Do I need to add the static variable _locker to some other class? with which the Foos have access?

Yes.

Each private type Foo<T> with different arguments T has its own static _locker object. You can inherit Foo from the base class and put a static object there. Then all types will use the same instance.

+7
source

Can

 public class Foo { protected static readonly object _locker = new object(); } public class Foo<T> : Foo { public void FooMethod(object stateInfo) { if (!Monitor.TryEnter(_locker)) { return; } try { // Logic here } finally { Monitor.Exit(_locker); } } } 
+6
source

You're right. Each unique T type specified in the code causes the CLR to generate a new specific type for Foo<T> , and each of them has its own set of static elements.

You can rebuild your code to look like this. This is just one of many valid variations.

 public class Foo { private static readonly object _locker = new object(); public void FooMethod(object stateInfo) { // Don't let threads back up; just get out if (!Monitor.TryEnter(_locker)) { return; } try { // Logic here } finally { Monitor.Exit(_locker); } } } public class Foo<T> { public void FooMethod(object stateInfo) { Foo.FooMethod(stateInfo); } } 

Also, keep in mind that you can start a timer with an infinite period to prevent the callback from being executed more than once. Call Change again at the end of FooMethod to queue the timer again. Since you have several timers, everyone will immediately have several simultaneous launches of FooMethod , but at least now there will be only one active call per timer. This is not exactly what you asked for, but I thought I would point it out anyway.

 _timers.Add(new Timer(foo.FooMethod, _timers.Count, 10000, Timeout.Infinite)); public class Foo<T> { public void FooMethod(object stateInfo) { try { // Logic here } finally { int index = (int)stateInfo; _timers[index].Change(10000, Timeout.Infinite); } } } 
+2
source

Please make this class nonequivalent. It will require your needs.

 public class Foo { private static readonly object _locker = new object(); public void FooMethod(object stateInfo) { // Don't let threads back up; just get out if (!Monitor.TryEnter(_locker)) { return; } try { // Logic here } finally { Monitor.Exit(_locker); } } } 
0
source

All Articles