以下代码是可重入且线程安全的吗?

时间:2011-10-05 16:55:35

标签: c# .net windows-services thread-safety reentrancy

以下代码是否可重入?

如果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());
    }

2 个答案:

答案 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();。您将每次创建一个新对象并锁定它。