65.9K
CodeProject 正在变化。 阅读更多。
Home

Mutex、Semaphore 与糟糕的发型之间

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.91/5 (7投票s)

2022 年 10 月 28 日

CPOL

5分钟阅读

viewsIcon

4698

互斥锁(Mutex)或信号量(Semaphore)用于提供非递归语义,因此您的程序或代码块只会运行一次 — 无需发胶...

引言

互斥锁信号量信号量互斥锁 — 尽管这两个名字听起来有点像医生可能会开的药,但互斥锁和信号量是计算机编程中的两个基本概念。但在我们解释这些概念是什么之前,让我们从头开始 — 当我们说“从头开始”时,我们指的是计算机程序的早期:糟糕的发型、大量的发胶和变薄的臭氧层。

您可能知道,或者如果您是老一辈,甚至可能还记得,在 80 年代和 90 年代初那个快乐的时代,在单台机器上可以一遍又一遍地同时运行一个程序:多个窗口叠在一起打开,您可以继续打开越来越多的同一程序的窗口。有时,这会因为缺乏计算机资源而导致崩溃。

如今,在大多数情况下,我们希望确保我们的程序在每台机器上只运行一次。例如,想想在同一台电脑上同时打开同一个 Excel 文档两次,并且有两个人分别编辑。

显然,除非我们重命名一个文档,否则如何管理同一文件两个实例中的更改?因此,MS Office 允许您一次只运行一个文档实例。让我们也假设我们拥有一款由办公室里的人使用的会计软件。在同一台机器上多次运行它没有意义。这也是用户友好设计的问题。如果用户没有意识到软件正在运行并启动了一个新实例,它将不会运行,而是将焦点转移到已在运行的实例上。

还有另一方面:有时,我们需要确保我们的代码的某些部分不会同时访问共享资源。将您的代码想象成您正在运行铁路网格:您不希望两列火车同时在同一条轨道上运行 — 我们希望它们同步,并且每列火车都按照其独特的时刻表运行。我们的程序需要与其所有组件和资源同步运行(尽管有些程序是异步运行的)。

现在您已经理解了问题,我们可以介绍一种解决方案:Mutex,它代表Mutual Exclusion Object(互斥对象)。C++ 标准库提供了 std::mutex,它包含一种机制,用于保护共享资源不被多个线程或实例同时访问。

互斥锁是一种原始类型,提供独占的、非递归的所有权语义。

拥有互斥锁的程序、程序中的线程或代码块都会受到保护,因此其他实例或线程将无法运行相同的程序、线程或代码块 — 它们将被锁定,这将确保在任何给定时间只运行一次。

当另一个资源已锁定该互斥锁时,尝试获取该互斥锁的所有权将返回 false 值,因此调用方知道它已被锁定。回到我们的例子,如果我们的会计软件的互斥锁被锁定,我们将找到已经运行的软件实例并将焦点转移到它上面。

将互斥锁想象成语音信箱 — 当有人打电话给您的固定电话并开始在您的语音信箱中录制消息时,其他人无法同时致电并留下消息 — 语音信箱被锁定。一旦一个人完成录制消息,另一个人就可以致电并留下消息。“互斥锁”在这种情况下是本地的,仅限于您的语音信箱。您可以给其他人留言,但在有人录制消息期间,您的特定语音信箱被锁定。当然,您可以设计一个可以一次录制五到十条消息的语音信箱,但大多数语音信箱的设计都只允许一次录制。这就是互斥锁的基本思想 — 您目前不需要了解更多。

信号量 — 一切都始于火车信号

控制对资源的访问的另一种方法是使用信号量,它们帮助我们同步程序。这种方法是由荷兰计算机科学家 Edsger W. Dijkstra 发明的,他最初在 1965 年将信号量设计为火车信号方法。信号量是线程之间共享的变量,可以简化为队列计数器的数据结构。计数器被初始化为 0 或大于 0 的值。使用这种结构,信号量执行两个非常简单的核心操作。

wait(等待) — 当信号量获得等待时,如果计数器不为 0,其他线程仍然可以使用它。因此,如果初始值为十,这意味着我们允许十个线程使用该资源,并且在它们中的每一个获取信号量时,计数器会递减直到达到 0。

Signal(信号)或 release(释放)一旦线程完成使用资源,就使用信号或释放操作来释放信号量,在这种情况下,计数器会增加。

如果这一切都太令人困惑,那就把信号量想象成新冠疫情期间便利店的保安:在任何给定时刻,只有少数人被允许待在封闭的店内。有一个队列,然后允许一个人进入。在信号量中,“wait”表示允许某人进入,并将可以进入的人数计数器减一,如果计数器现在为 0,则没有人可以进入。一旦有人离开商店(“release”),计数器就会增加一,这样另一个人就可以进入。您也可以将其与火车信号机制进行比较,这是其最初的设计。

您可能会问自己互斥锁和信号量有什么区别。简单的答案是,互斥锁使用锁定机制,而信号量使用信号机制。当然,还有其他区别,以及更多关于互斥锁和信号量的知识,我无法在一篇文章中全部涵盖。

历史

  • 2022 年 10 月 28 日:初始版本
© . All rights reserved.