【问题标题】:How do mutexes really work?互斥锁是如何真正工作的?
【发布时间】:2012-07-31 00:25:20
【问题描述】:

互斥锁背后的想法是在任何时候只允许一个线程访问一段内存。如果一个线程锁定了互斥体,任何其他锁定尝试都将阻塞,直到第一个解锁。然而,这是如何实现的呢?要锁定自己,互斥锁必须在某个地方设置一个表示它已锁定的位置。但是,如果第二个互斥锁同时读取第一个互斥锁,该怎么办。更糟糕的是,如果他们同时锁定互斥锁怎么办?互斥体将屈服于它旨在防止的相同问题。

互斥锁是如何工作的?

【问题讨论】:

    标签: c++ multithreading concurrency mutex


    【解决方案1】:

    低级原子操作。这些本质上是在硬件中实现的互斥锁,除了您只能以原子方式执行极少数操作。

    考虑以下等效伪代码:

    mutex global_mutex;
    void InterlockedAdd(int& dest, int value) {
        scoped_lock lock(mutex);
        dest += value;
    }
    int InterlockedRead(int& src) {
        scoped_lock lock(mutex);
        return src;
    }
    void InterlockedWrite(int& dest, int value) {
        scoped_lock lock(mutex);
        dest = value;
    }
    

    这些功能是由 CPU 以指令的形式实现的,它们在不同程度上保证了线程之间的一致性。确切的语义取决于所讨论的 CPU。 x86 提供顺序一致性。这意味着操作的行为就像它们是按某种顺序按顺序发出的一样。这显然涉及到一些阻塞。

    您可以准确地推测原子操作可以用互斥体来实现,反之亦然。但通常,原子操作由硬件提供,然后由操作系统在它们之上实现互斥锁和其他同步原语。这是因为有些算法不需要完整的互斥体并且可以操作所谓的“无锁”,这意味着只使用原子操作来实现一些线程间的一致性。

    【讨论】:

      【解决方案2】:

      过去使用的一个简单实现是使用 CPU 级别的原子“锁定和交换”指令。这是一条特殊指令,可以将给定值与某个内存位置中的值进行原子交换。

      线程可以通过尝试将 1 值交换到内存位置来获取这样的互斥锁。如果该值返回为 0,则线程将假定它具有互斥锁并继续。否则,如果返回值为 1,则线程将知道某个 other 线程当前具有互斥锁。在这种情况下,它会等到重试。

      以上是对简单系统中可能发生的事情的高度简化概述。如今,真正的操作系统要复杂得多。

      【讨论】:

      • 这没有回答问题。如果两个线程同时“读取和交换”会怎样。然后两者都返回 0。
      • @user1146657:“锁定和交换”操作的重点在于它是原子的,并且CPU(s)确保只有一个线程可以在任何时候执行它给定的时间。所以根据定义,两个线程不能同时进行。 CPU 专门为此目的而设计。
      【解决方案3】:

      这里是对互斥锁需要什么工作的快速概述,它是我完整文章How does a mutex work?的缩写形式@

      • 内存中有一个整数表示锁定状态,值为 1 或 0。
      • 互斥体需要一个原子compare_and_swap 函数,它可以原子地尝试修改该值并报告它是否成功。这允许线程同时检查和修改状态。
      • 操作系统需要提供一个函数在互斥锁被锁定的情况下等待。在 Linux 上,低级函数是 futex。这会将线程放入队列中,并监控内存中的整数。
      • 所涉及的操作还包括数据围栏,以防止内存中的修改在锁定之前可见,并且在锁定之后完全可用。

      【讨论】:

        【解决方案4】:

        您所需要的只是以原子方式进行。它可以由硬件提供,例如原子比较和交换指令,也可以由操作系统通过系统调用提供。一旦它进入操作系统域,就很容易确保只有一个线程试图锁定互斥锁。

        在实践中,这两种方法是结合在一起的。参见例如 Linux 的 futexes。

        【讨论】:

          猜你喜欢
          • 2018-03-27
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2016-04-28
          • 1970-01-01
          • 2021-06-21
          • 2012-09-04
          相关资源
          最近更新 更多