1

下面的代码是可重入的吗?

它是线程安全的,ifthis.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());
    }
4

2 回答 2

8

不,这根本不是线程安全的。由于对象是线程本地的,因此锁定无效。它需要由所有调用线程共享。一旦你解决了这个问题,你就不需要使用互锁增量,因为锁会序列化执行。

作为一般规则,您应该将其置于locker与您要保护的资源相同的级别。如果资源由实例拥有,那么应该是locker. 同样,如果资源归类所有。

至于重入,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为 volatile。

于 2011-10-05T16:57:31.923 回答
4

绝对不。这是你的问题object locker = new object();。您将创建一个新对象并每次都锁定它。

于 2011-10-05T16:57:43.253 回答