I have a situation where, for testing, I only want my timer method (FooMethod) to run one at a time. In the example below, FooMethod is passed as the delegate to a timer. There are many concrete instances of this class. I thought that by making _locker static, only one instance of FooMethod() would process at a time. But when I run the app, multiple threads are getting past the TryEnter() line at a time.
This is how I'm adding each class to a new timer. This is done, in a loop, for each foo instance:
_timers.Add(new Timer(foo.FooMethod, null, 0, 10000));
And this is the class that has that 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: Normally, _locker isn't static; I don't want the same thread entering the method before it got a chance to complete. I changed it to static here for testing.
My first thought is that maybe this isn't working because the class is generic? And that each concrete class is actually its own class and they don't share the _locker variable? Is that true? If that's true how should I have the concrete classes share a _locker variable? Do I need to add a static _locker variable to some other class to which the Foos have access?
Do I need to add a static _locker variable to some other class to which the Foos have access?
Yes.
Each closed Foo<T>
type, with different T
arguments, has its own static _locker object. You could make Foo inherit from a base class, and put the static object there. Then, all the types would use the same instance.
Maybe
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);
}
}
}
You are correct. Each unique type T
referenced in code causes the CLR to generate a new concrete type for Foo<T>
and each has its own set of static members.
You could restructure your code to look like the following. It is but one among 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 the timer with an infinite period
to prevent the callback from executing more than once. Call Change
again at the end of FooMethod
to queue the timer again. Since you have multiple timers all going at once you will still have multiple concurrent executions of FooMethod
going simultaneously, but at least now there will only be one active call per timer. That is not exactly what you asked for, but I thought I would point this 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);
}
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With