Cod*_*Try 2 c unix semaphore ipc
I have a very basic doubt.
Run Code Online (Sandbox Code Playgroud)
当进程正在等待信号量时,它会进入睡眠状态。所以它无法轮询信号量值。
内核是否轮询信号量值,如果可用,向所有等待它的进程发送信号?如果是这样,内核的开销不会太大。
或者 signal() 调用在内部通知所有等待信号量的进程。请让我知道这一点。
当操作系统被另一个进程告知它已经完成了信号量时,操作系统会再次调度该进程。
信号量只是与操作系统调度程序交互的方式之一。
内核不轮询信号量;它不需要。每次进程调用sem_post()(或等效)时,都涉及与内核的交互。内核在此期间所做的sem_post()是查找先前sem_wait()在同一信号量上调用的任何进程。如果一个或多个进程调用了sem_wait(),它会选择具有最高优先级的进程并对其进行调度。这表现为sem_wait()最终返回并且该进程继续执行。
这是如何在幕后实施的
从根本上说,内核需要实现一种叫做“原子测试和设置”的东西。这是一种操作,其中可以通过某个变量的值进行测试,如果满足某个条件(例如值 == 0),则更改变量值(例如值 = 1)。如果成功,内核会做一件事,(比如调度一个进程),如果这不成功(因为条件 value==0 是假的)内核会做一些不同的事情(比如把一个进程放在不要 -日程表)。“原子”部分是做出这个决定时没有其他任何东西能够同时查看和更改相同的变量。
有几种方法可以做到这一点。一种是挂起所有进程(或至少是内核中的所有活动),这样就不会同时测试变量的值。那不是很快。
例如,Linux 内核曾经有一个叫做 Big Kernel Lock 的东西。我不知道这是否用于处理信号量交互,但这是操作系统曾经用于原子测试和集的那种东西。
如今,CPU 具有原子测试和设置操作码,这要快得多。好的 ole' 摩托罗拉 68000 很久以前就有过其中之一。像 PowerPC 和 x86 这样的 CPU 需要很多很多年才能获得相同类型的指令。
如果你在 linux 中扎根,你会发现提到futexes. futex 是一个快速互斥体——它依赖于 CPU 的测试/设置指令来实现一个快速mutex信号量。
在硬件中发布信号量
一个变体是邮箱信号量。这是信号量的特殊变体,在硬件需要在 DMA 传输结束时唤醒进程的某些系统类型中非常有用。邮箱是内存中的一个特殊位置,写入时会引发中断。内核可以将其转换为信号量,因为当引发该中断时,它会经历与调用sem_post().
这非常方便;设备可以DMA将大量数据传输到一些预先安排的缓冲区,并通过少量DMA传输到邮箱。内核处理中断,如果一个进程之前调用sem_wait()了邮箱信号量,内核就会调度它。该进程也知道这个预先安排的缓冲区,然后可以处理数据。
在实时 DSP 系统上,这非常有用,因为它非常快且延迟非常低;它允许进程以很小的延迟从某个设备接收数据。相比之下,使用read()/write()将数据从设备传输到进程的完整设备驱动程序堆栈的替代方法非常慢。
速度
信号量交互的速度完全取决于操作系统。
对于像 Windows 和 Linux 这样的操作系统,上下文切换时间相当缓慢(大约几微秒,如果不是几十微秒)。基本上这意味着当一个进程调用类似的东西时sem_post(),内核正在做很多不同的事情,同时它有机会最终将控制权返回给进程。这段时间它在做什么,嗯,几乎任何事情!
如果程序利用了大量的线程,而且都很快他们之间使用信号灯互动,相当多的时间,输给了sem_post()和sem_wait()。这强调了sem_wait()在调用下一个进程之前在进程返回后做大量的工作sem_post()。
然而在像 VxWorks 这样的操作系统上,上下文切换时间快如闪电。也就是说,当调用 sem_post() 时,内核中运行的代码很少。结果是信号量交互效率更高。此外,像 VxWorks 这样的操作系统的编写方式是为了保证完成所有这些sem_post()/sem_wait()工作所需的时间是恒定的。
这会影响这些系统上的软件架构。在 VxWorks 上,上下文切换很便宜,因此让大量线程都执行非常小的任务几乎没有损失。在 Windows / Linux 上,更多的是强调相反的内容。
这就是为什么像 VxWorks 这样的操作系统非常适合硬实时应用程序,而 Windows / Linux 则不然。
Linux PREEMPT_RT 补丁集的部分目的是在这样的操作期间改善 linux 内核的延迟。例如,它将许多设备中断处理程序(设备驱动程序)推送到内核线程中;这些几乎就像任何其他线程一样被安排。这个想法是减少内核正在完成的工作量(并由内核线程完成更多工作),以便它仍然必须自己完成的工作(例如处理sem_post()/ sem_wait())花费更少的时间并且更加一致这需要多长时间。它仍然不是延迟的硬保证,但这是一个相当不错的改进。这就是我们所说的软实时内核。但影响是机器的整体吞吐量可能会降低。
信号
信号是令人讨厌的、可怕的东西,它们确实妨碍了使用 sem_post() 和 sem_wait() 之类的东西。我像躲避瘟疫一样避开它们。
如果您在 Linux 平台上并且确实必须使用信号,请仔细查看signalfd(手册页)。这是处理信号的好得多的方法,因为您可以选择在方便的时间接受它们(简单地通过调用read()),而不必在它们发生时立即处理它们。当然,如果您正在使用epoll()或select()在程序中的任何地方使用,那么signalfd就是要走的路。
| 归档时间: |
|
| 查看次数: |
1334 次 |
| 最近记录: |