gpt4 book ai didi

c - 进程如何知道信号灯可用

转载 作者:行者123 更新时间:2023-12-02 09:16:23 24 4
gpt4 key购买 nike

I have a very basic doubt. 

当进程正在等待信号量时,它将进入睡眠状态。
因此,它无法轮询信号量值。

内核是否轮询信号量值(如果可用)向所有等待它的进程发送信号?如果是这样,那么对于内核来说不会有太多的开销。

还是signal()调用在内部通知所有等待信号量的进程。
请让我知道这一点。

最佳答案

当另一个进程告诉操作系统它已使用信号量时,操作系统将再次调度该进程。

信号量只是与OS调度程序进行交互的方式之一。

内核不会轮询信号量。它不需要。每次进程调用sem_post()(或等效命令)时,都会涉及与内核的交互。内核在sem_post()期间执行的操作是查找先前在同一信号量上调用过sem_wait()的所有进程。如果一个或多个进程调用了sem_wait(),它将选择优先级最高的进程并对其进行调度。这显示为sem_wait()最终返回并且该进程继续执行。

幕后如何实现

从根本上说,内核需要实现一种称为“原子测试和设置”的东西。这是一种操作,其中可以测试某个变量的值,并且如果满足某个条件(例如value == 0),则更改变量值(例如value = 1)。如果成功,内核将做一件事(例如调度一个进程),如果不成功(因为条件value == 0为false),内核将做些不同的事情(例如将一个进程放到“不要”上)时间表清单)。 “原子”部分是做出此决定时,其他任何事情都无法同时查看和更改同一变量。

有几种方法可以做到这一点。一种是挂起所有进程(或至少内核中的所有 Activity ),以便没有别的东西可以同时测试变量的值。那不是很快。

例如,Linux内核曾经有一个叫做“大内核锁”的东西。我不知道这是否用于处理信号量交互,但这是操作系统过去用于原子测试和设置的那种东西。

如今,CPU具有原子测试和设置操作码,这要快得多。很好的摩托罗拉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这样的OS上,上下文切换时间很快。那就是当sem_post()被调用时内核中几乎没有代码可以运行。结果是信号量交互更加有效。而且,像VxWorks这样的OS都是以这样的方式编写的,以确保完成所有sem_post() / sem_wait()工作所需的时间是恒定的。

这会影响这些系统上软件的体系结构。在上下文切换很便宜的VxWorks上,拥有大量线程来完成非常小的任务几乎没有什么代价。在Windows / Linux上,更多的是相反的。

这就是为什么像VxWorks这样的OS对于硬实时应用程序非常出色而Windows / Linux却不如此的原因。

Linux PREEMPT_RT补丁集的部分目的是在此类操作期间改善Linux内核的延迟。例如,它将大量设备中断处理程序(设备驱动程序)推送到内核线程中。这些调度几乎与其他任何线程一样。这个想法是为了减少内核正在完成的工作量(并由内核线程完成更多的工作),以便它仍然必须自己完成的工作(例如处理sem_post() / sem_wait())花费的时间更少,而且更多这需要多长时间。它仍然不是延迟的硬保证,但这是一个相当不错的改进。这就是我们所说的软实时内核。但是,影响是机器的整体吞吐量可能会降低。

表示

信号是令人讨厌的,可怕的事情,实际上阻碍了使用诸如sem_post()和sem_wait()之类的事情。我像瘟疫一样避开它们。

如果您使用的是Linux平台,则必须使用信号,请认真看一看signalfd(man page)。这是处理信号的一种更好的方法,因为您可以选择在方便的时间(简单地称为read())接受它们,而不必在它们出现时立即进行处理。当然,如果您在程序中的任何地方都使用epoll()select(),那么signalfd是您的最佳选择。

关于c - 进程如何知道信号灯可用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46871224/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com