我有一种情况,为了测试,我只希望我的计时器方法(FooMethod)一次运行一个。在下面的示例中,FooMethod作为委托传递给计时器。这个类有很多具体的例子。我认为通过使_locker静态,只有一个FooMethod()实例会一次处理。但是当我运行应用程序时,多个线程一次超过TryEnter()行。
这就是我将每个类添加到新计时器的方法。这是在循环中为每个foo实例完成的:
_timers.Add(new Timer(foo.FooMethod, null, 0, 10000));
这是具有该方法的类:
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);
}
}
}
注意:通常情况下,_locker不是静态的;在有机会完成之前,我不希望同一个线程进入该方法。我把它改为静态测试。
我的第一个想法是,这可能不起作用,因为这个类是通用的?并且每个具体类实际上是它自己的类,它们不共享_locker变量?真的吗?如果这是真的,我应该如何让具体类共享一个_locker变量?我是否需要将静态_locker变量添加到Foos可以访问的其他类?
答案 0 :(得分:7)
我是否需要将静态_locker变量添加到其他类中 Foos可以访问哪些?
是。
每个具有不同Foo<T>
参数的已关闭T
类型都有自己的静态_locker对象。你可以让Foo继承自基类,并将静态对象放在那里。然后,所有类型都将使用相同的实例。
答案 1 :(得分:6)
也许
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);
}
}
}
答案 2 :(得分:2)
你是对的。代码中引用的每个唯一类型T
都会导致CLR为Foo<T>
生成新的具体类型,并且每个类型都有自己的静态成员集。
您可以将代码重构为如下所示。它只是众多有效变体中的一种。
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);
}
}
另外,请记住,您可以使用无限period
启动计时器,以防止回调执行多次。再次在Change
结束时调用FooMethod
以再次对计时器进行排队。由于你有多个计时器同时进行,你仍然会同时执行FooMethod
的多个并发执行,但至少现在每个计时器只有一个活动的通话。这不完全是你所要求的,但我想我还是会指出这一点。
_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);
}
}
}
答案 3 :(得分:0)
请将此课程设为非通用类型。这将满足您的需求。
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);
}
}
}