单线程方案是否需要Volatile.Write?

时间:2019-04-12 13:26:39

标签: c# multithreading volatile

场景:

我有一个可以从许多线程调用的类。 就像这样:

internal sealed class ThreadLocalMarker : IDisposable
{
    [ThreadStatic]
    private static int _counter;

    private bool _disposed;

    public ThreadLocalMarker()
    {
        _counter++;
    }

    public static bool Entered => _counter > 0;

    public void Dispose()
    {
        if (_disposed)
        {
            return;
        }
        _counter--;
        _disposed = true;
    }
}

ThreadStatic变量_counter用于创建一个计数器变量,该变量将分配给调用该类的每个线程。

现在我已经进行了这样的单元测试

[Test]
    public void SingleThreadReadsCorrectValue()
    {
        using (new ThreadLocalMarker())
        {
            Assert.IsTrue(ThreadLocalMarker.Entered);
        }
        Assert.IsFalse(ThreadLocalMarker.Entered);
    }

问题:

第二个断言始终失败。

解决方法:

我的朋友建议,这可能是因为尽管在使用退出后将调用Dispose,但计数器值并未及时增加,因为处理器会重新排序操作以进行优化,因此,当调用Entered时,_counter的值仍不会减少。

他建议我在Dispose()中写这个:

Thread.VolatileWrite(ref _counter, _counter - 1);

问题:

  1. 因为我的测试中只有一个线程,所以我需要Volatile.Write吗?
  2. 读取_counter值时是否不必使用Volatile.Read?
  3. 我可以为_counter使用volatile关键字吗?
  4. 我们什么时候应该真正使用volatile,在这种情况下,我们甚至需要使用ThreadStatic吗? 我的想法是,当我们有许多线程访问线程之间共享的变量的同一副本时,我们需要使用volatile。但是对于_counter变量,它被声明为ThreadStatic,这意味着“静态字段的值对于每个线程都是唯一的”。因此,每个线程都有自己的_counter值。 在这种情况下,这里并不是完全不需要使用volatile和内存屏障,因为不同的线程甚至不共享_counter的相同副本。
  5. 最后,为什么我的测试的最后一个断言会不一致地失败?

问题2和3的一些代码示例对我来说将是额外的收获!

0 个答案:

没有答案