锁、内存屏障、信号量之间的区别



本文: http://www.aristeia.com/Papers/DDJ_Jul_Aug_2004_revised.pdf (第12页(似乎在锁和记忆屏障之间有所不同

我想知道锁、内存屏障和信号量有什么区别?

(虽然其他问题可能会提到锁和同步对象之间的区别,但我没有发现锁和内存屏障之间的区别(

内存屏障(也称为围栏(是一种硬件操作,它确保对全局的不同读取和写入顺序可见商店。 在典型的现代处理器上,内存访问是管道,并且可能会无序发生。 内存屏障确保这不会发生。 完整的内存屏障将确保所有负载以及之前发生的存储,先于任何加载或随后的存储它。 (许多处理器具有支持部分障碍;例如,在 Sparc 上,一个 membar #StoreStore确保之前发生的所有存储都将在之后发生的任何存储之前对所有其他进程可见它。

这就是记忆屏障所做的一切。 它不会阻塞线程,或者什么。

互斥体和信号量是更高级别的基元,在操作系统。 请求互斥锁的线程将阻塞,并且由操作系统暂停其执行,直到该互斥锁免费。 这操作系统中的内核代码将按顺序包含内存屏障指令实现互斥锁,但它的作用远不止于此;记忆屏障指令将暂停硬件执行(所有线程(,直到已满足必要条件 — 在大多数,整个处理器都会停止这次。 当您尝试锁定互斥锁,另一个线程已经拥有它,操作系统将挂起您的线程(并且只有您的线程 — 处理器继续执行其他线程(,直到持有互斥锁的人释放它,这可能是几秒钟、几分钟甚至几天。 (当然,如果它不仅仅是一个几百毫秒,这可能是一个错误。

最后,信号量和互斥体;互斥锁可被视为计数为 1 的信号量。

    内存
  • 屏障是一种对内存访问进行排序的方法。 编译器和 CPU 可以更改此顺序进行优化,但在多线程环境中,这可能是一个问题。 与其他线程的主要区别在于线程不会因此而停止。
  • 或互斥锁确保代码只能由 1 个线程访问。 在本节中,可以将环境视为单线程,因此不需要内存障碍。
  • 信号量基本上是一个可以增加(v(((或减少(p(((的计数器。 如果计数器为 0,则 p(( 将暂停线程,直到计数器不再为 0。 这是一种同步线程的方法,但我更喜欢使用互斥体或条件变量(有争议,但这是我的观点(。当初始计数器为 1 时,信号量称为二进制信号量,它类似于锁。
锁和信号量

之间的一个很大区别是线程拥有锁,因此没有其他线程应该尝试解锁,而信号量则不是这种情况。

现在的简单解释。

是这段代码是否可以继续的原子测试

lock (myObject)
{
    // Stuff to do when I acquire the lock
}

这通常是单个 CPU 指令,用于测试变量并将其设置为单个原子操作。 更多在这里,http://en.wikipedia.org/wiki/Test-and-set#Hardware_implementation_of_test-and-set_2

记忆屏障

是对处理器的提示,表明它不能无序地执行这些指令。 没有它,指令可能会无序执行,就像在双重检查锁定中一样,两个空检查可以在锁定之前执行。

Thread.MemoryBarrier();
public static Singleton Instance()
{
    if (_singletonInstance == null)
    {
        lock(myObject)
        {
            if (_singletonInstance == null)
            {
                _singletonInstance = new Singleton();
            }
        }
    }
}

这也是一组 CPU 指令,它们实现内存屏障以明确告诉 CPU 它不能无序执行。

信号灯

与锁类似,只是它们通常用于多个线程。 例如,如果您可以处理 10 个并发磁盘读取,您将使用信号量。 根据处理器的不同,这要么是它自己的指令,要么是测试和设置指令,加载更多围绕中断的工作(例如在ARM上(。

最新更新