相关疑难解决方法(0)

volatile和readonly应该互相排斥吗?

假设我正在设计一个包装内部集合的线程安全类:

public class ThreadSafeQueue<T>
{
    private readonly Queue<T> _queue = new Queue<T>();

    public void Enqueue(T item)
    {
        lock (_queue)
        {
            _queue.Enqueue(item);
        }
    }

    // ...
}
Run Code Online (Sandbox Code Playgroud)

基于我的另一个问题,上面的实现是错误的,因为当它的初始化与其使用同时执行时可能会出现种族危险:

ThreadSafeQueue<int> tsqueue = null;

Parallel.Invoke(
    () => tsqueue = new ThreadSafeQueue<int>(),
    () => tsqueue?.Enqueue(5));
Run Code Online (Sandbox Code Playgroud)

上面的代码是可接受的非确定性的:该项目可能会或可能不会入队.但是,在当前的实现中,它也被破坏了,并且可能引起不可预测的行为,例如抛出IndexOutOfRangeException,NullReferenceException多次将相同的项目入队,或者陷入无限循环.这是因为Enqueue调用可能将新实例分配给局部变量tsqueue之后但内部_queue字段的初始化完成(或似乎完成)之前运行.

Per Jon Skeet:

在将对新对象的引用分配给实例之前,Java内存模型不能确保构造函数完成.Java内存模型经历了1.5版的重新加工,但是在没有volatile变量的情况下,双重检查锁定仍然被破坏(如在C#中).

可以通过向构造函数添加内存屏障来解决此种族危险:

    public ThreadSafeQueue()
    {
        Thread.MemoryBarrier();
    }
Run Code Online (Sandbox Code Playgroud)

同样,通过使字段变化可以更简洁地解决:

    private volatile readonly Queue<T> _queue = new …
Run Code Online (Sandbox Code Playgroud)

.net c# concurrency multithreading volatile

6
推荐指数
1
解决办法
449
查看次数

标签 统计

.net ×1

c# ×1

concurrency ×1

multithreading ×1

volatile ×1