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

Giu*_*olo 1 .net c# 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());
    }
Run Code Online (Sandbox Code Playgroud)

Dav*_*nan 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);
Run Code Online (Sandbox Code Playgroud)

注意:您应该声明NextToExecuteIndex为volatile.

  • 评论1:你所做的一切听起来不错.实例由基类和派生类组成.它仍然是同一个对象.没有问题.评论2:你需要比较和交换,因为我已经编辑了要显示的答案. (2认同)