以下代码是否可重入?
如果this.NextToExecuteIndex
被声明为private int NextToExecuteIndex = 0;
并且未在其他地方计算,那么它是否是线程安全的?
protected override void Poll(object sender, System.Timers.ElapsedEventArgs e)
{
int index;
object locker = new object();
lock (locker)
{
Interlocked.Increment(ref this.NextToExecuteIndex);
if (this.NextToExecuteIndex >= this.ReportingAgentsTypes.Count())
{
this.NextToExecuteIndex = 0;
}
index = this.NextToExecuteIndex;
}
var t = this.ReportingAgentsTypes[index];
Console.WriteLine(t.ToString());
}
答案 0 :(得分:8)
这根本不是线程安全的。锁定无效,因为该对象是线程的本地对象。它需要由所有调用线程共享。修复后,您不需要使用互锁增量,因为锁序列执行。
作为一般规则,您应将locker
置于与您保护的资源相同的级别。如果资源由实例拥有,那么应该locker
。同样,如果资源归类所有。
至于re-entrancy,lock
关键字使用可重入锁,即如果该线程持有锁,则允许相同线程进入。这可能不是你想要的。但是如果你有一个不可重入的锁定,那么你就会因为重入的呼叫而陷入僵局。而且我认为你也不想这样。
你看起来想要一个环绕增量。只要不修改集合,就可以通过互锁操作实现,即无锁定。如果是这样,那么可以这样写:
do
{
int original = this.NextToExecuteIndex;
int next = original+1;
if (next == this.ReportingAgentsTypes.Count())
next = 0;
}
while (Interlocked.CompareExchange(ref this.NextToExecuteIndex, next, original) != original);
注意:您应将NextToExecuteIndex
声明为易失性。
答案 1 :(得分:4)
绝对不是。这是您的问题object locker = new object();
。您将每次创建一个新对象并锁定它。