7

这篇文章:http ://www.aristeia.com/Papers/DDJ_Jul_Aug_2004_revised.pdf (第12页)似乎在锁和内存屏障之间有所不同

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

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

4

3 回答 3

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

锁和信号量之间的一个很大区别是线程拥有锁,所以没有其他线程应该尝试解锁,而信号量则不是这样。

于 2012-05-11T13:41:03.950 回答
10

内存屏障(也称为栅栏)是一种硬件操作,可确保对全局可见存储的不同读取和写入的顺序。在典型的现代处理器上,内存访问是流水线的,并且可能会出现乱序。内存屏障确保不会发生这种情况。完整的内存屏障将确保在它之前的所有加载和存储都发生在它之后的任何加载或存储之前。(许多处理器支持部分屏障;例如,在 Sparc 上,a membar #StoreStore确保在它之后发生的任何存储之前发生的所有存储对所有其他进程都是可见的。)

这就是内存屏障的全部作用。它不会阻塞线程或任何东西。

互斥量和信号量是更高级别的原语,在操作系统中实现。请求互斥锁的线程将阻塞,并由操作系统暂停其执行,直到该互斥锁空闲。操作系统中的内核代码将包含内存屏障指令以实现互斥锁,但它的作用远不止于此;内存屏障指令将暂停硬件执行(所有线程),直到满足必要条件——最多一微秒左右,整个处理器在这段时间内停止。当你试图锁定一个互斥锁,而另一个线程已经拥有它时,操作系统将暂停你的线程(并且只有你的线程——处理器继续执行其他线程),直到持有互斥锁的人释放它,这可能是几秒钟、几分钟或双数日。(当然,如果超过几百毫秒,它'

最后,信号量和互斥量并没有太大区别。互斥量可以被认为是计数为 1 的信号量。

于 2012-05-11T14:05:57.647 回答
2

现在简单解释一下。

是对这段代码是否可以进行的原子测试

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 上)。

于 2012-05-11T13:29:16.327 回答