锁,记忆障碍,信号量之间的区别

时间:2012-05-11 13:14:11

标签: c++ multithreading

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

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

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

3 个答案:

答案 0 :(得分:8)

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

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

答案 1 :(得分:8)

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

这就是记忆障碍。它不会阻塞线程,或 任何东西。

互斥体和信号量是更高级别的灵长类动物,在实现中 操作系统。请求互斥锁的线程将阻塞,和 执行程序暂停执行,直到该互斥锁是空闲的。该 OS中的内核代码将按顺序包含内存屏障指令 实现互斥,但它做得更多;记忆障碍 指令将暂停硬件执行(所有线程),直到 必要条件已达到 - 一微秒左右 大多数,整个处理器停止这段时间。当你尝试 锁定互斥锁,另一个线程已经拥有它,操作系统将暂停 你的线程(只有你的线程 - 处理器继续 执行其他线程)直到持有互斥锁的人释放它,哪个 可能是几秒,几分钟甚至几天。 (当然,如果它不仅仅是一个 几百毫秒,这可能是一个错误。)

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

答案 2 :(得分: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上)。