锁助手的线程安全使用(关于内存屏障)

本文关键字:于内存 内存 线程 安全 | 更新日期: 2023-09-27 18:01:12

通过锁定助手,我指的是可通过using语句实现锁定的一次性对象。例如,考虑Jon Skeet的MiscUtil:中SyncLock类的典型用法

public class Example
{
    private readonly SyncLock _padlock;
    public Example()
    {
        _padlock = new SyncLock();
    }
    public void ConcurrentMethod()
    {
        using (_padlock.Lock())
        {
            // Now own the padlock - do concurrent stuff
        }
    }
}

现在,考虑以下用法:

var example = new Example();
new Thread(example.ConcurrentMethod).Start();

我的问题是,既然example是在一个线程上创建的,而ConcurrentMethod是在另一个线程中调用的,那么ConcurrentMethod的线程就不能忽略_padock在构造函数中的赋值(由于线程缓存/读写重新排序(,从而抛出NullReferenceException(在_padLock本身上(吗?

我知道用Monitor/lock锁定有内存屏障的好处,但当使用这样的锁助手时,我不明白为什么能保证这样的屏障。在这种情况下,据我所知,构造函数必须进行修改:

public Example()
{
    _padlock = new SyncLock();
    Thread.MemoryBarrier();
}

来源:了解低锁定技术在多线程应用中的影响

EDITHans-Passant认为线程的创建意味着内存障碍。那么:怎么样

var example = new Example();
ThreadPool.QueueUserWorkItem(s => example.ConcurrentMethod());

现在不一定要创建线程。。。

锁助手的线程安全使用(关于内存屏障)

不,您不需要做任何特殊的事情来确保创建内存屏障。这是因为几乎任何用于在另一个线程上执行方法的机制都会在调用线程上产生释放围栏屏障,在工作线程上产生捕获围栏

此外,作为切向关注的问题,Thread.Sleep也产生存储器屏障。这很有趣,因为有些人天真地使用Thread.Sleep来模拟线程交错。如果将此策略用于低锁定代码的故障排除,那么它可以很好地掩盖您试图找到的问题。