首页 > 解决方案 > 为什么我们需要单个 cpu 上的信号量?

问题描述

我读过我们在 linux kerenl 中使用信号量,并且我读过信号量即使在一个 cpu 中也有优势(我们只能运行一个进程\线程)。谁能给我一个信号量解决的问题的例子(在内核内部)?

在我看来,只有当我们有多个 cpu 时才会出现问题,因为两个进程可能会调用使用相同数据结构的系统调用,并且可能会导致问题。

谢谢您的帮助!

标签: semaphore

解决方案


您实际上并不需要一个以上的 CPU 来实现并发。多个 CPU 确实是“实现细节”,是您可以从中抽象出来的硬件怪癖。并发是程序的逻辑属性。您可以在没有多个 CPU 的情况下进行并发,并在没有“真正并发”的情况下使用多个 CPU。

考虑一个 Web 服务器。它必须是“并发的”,因为它必须一次服务多个客户端,一次保存有关多个连接的信息,并一次处理多个请求。你可以让它真正做到这一点,让多个 CPU 同时工作。然而,程序只需要出现一次做多件事。它也可以在一个 CPU 上运行并进行上下文切换以公平地服务于它的所有工作。Web 服务器一次执行多项操作的事实是其接口的一部分:连接的 I/O 是交错的,如果一个请求专门锁定了一个资源,另一个请求将不会开始尝试操作相同的资源,等等。编写没有并发的 Web 服务器会产生错误的程序。

信号量通过让您控制进程访问资源的方式来帮助您实现并发。您问,如果您有一个进程正在运行,那么另一个进程如何仅在一个内核的情况下同时运行。好吧,正如我所说,并发不需要多个核心。第一个过程可以暂停,第二个过程在第一个过程尚未完成时开始。这只是一个实现细节;从逻辑上讲,对于程序编写者来说,两个进程同时运行,无论是否有多个内核。如果程序是在没有信号量的情况下编写的(或者以其他方式破坏了并发性),那么即使在单核上也是错误的。从物理上讲,这是因为上下文切换可以在任何时候突然暂停一个计算并启动另一个计算,并且,如果没有信号量,新的活动线程将不知道它可以访问和不能访问哪些资源。从逻辑上讲,这将是因为进程同时运行,一旦您将自己从实现中抽象出来,并且通常,如果没有正确同步,同时运行的进程可以相互遍历。

对于适用于 OS 内核的示例,请考虑每个进程在逻辑上与所有其他进程同时运行。内核提供了使这种并发工作的实现。两个进程可能同时需要的资源是硬盘驱动器。内核中可能会使用信号量来跟踪给定驱动器当前是否忙于读取或写入。试图读取或写入同一个磁盘的进程将要求内核这样做,内核可以检查信号量以查看磁盘仍然繁忙并强制有问题的进程等待。现在,操作系统确实算作低级代码,所以在某些地方,是的,在单个 CPU 上运行时,您可能希望省略一些其他重要的并发保护措施,因为您的工作是处理此类实现细节,但更高级别的部分仍可能使用它们。

相反,考虑一个数字运算程序。假设它正在将大量数据的每个元素处理成一个大小相等的修改数据数组(一个函数map操作)。它可以使用多个 CPU 更快地执行此操作,但它也可以使用一个 CPU。程序的可观察行为是相同的,你永远不会从它的行为中知道它同时做多件事。数字进去,数字出来,谁在乎中间发生了什么?编写这样一个不能同时执行多项操作的程序不会产生逻辑错误的程序,只会产生缓慢的程序。这样的程序在单个 CPU 上运行时可能不需要信号量,因为它首先不需要并发。


推荐阅读