谁使用POSIX实时信号以及为什么使用?

32
我不是在开玩笑,我真的不理解。我刚读了一堆相关资料,但我还是想不通使用场景。我不是特别谈论API,因为它与signal()等东西相比的优势已经足够明显了。相反,实时信号似乎是用于用户空间生成的,但是用于什么目的呢?唯一的用途似乎是原始进程间通信,但是所有的指示都表明它们是一种糟糕的IPC形式(例如,笨拙、信息有限,不是特别高效等)。
那么,它们在哪里和如何使用呢?
4个回答

27

首先,注意Ben的答案是正确的。据我所知,POSIX中实时信号的整个目的是作为AIO、消息队列通知、定时器到期和应用程序定义信号(内部和进程间)的实时传递机制。

话虽如此,信号总体来说是一种非常糟糕的方法:

  • 信号处理程序是异步的,除非您确保它们不会中断异步信号不安全函数,否则它们只能使用异步信号安全函数,这严重限制了它们可以做什么。
  • 信号处理程序是全局状态。库不能使用信号而没有与调用程序的合同,关于它被允许使用哪些信号,是否允许使它们系统调用中断等等。而且通常来说,全局状态只是坏事情
  • 如果您使用sigwait(或Linux的signalfd扩展)而不是信号处理程序来处理信号,则它们与其他IPC/通知机制一样差,仍然存在潜在的劣势。

异步IO更好地通过忽略设计不良的POSIX AIO API实现,并创建一个线程来执行正常的阻塞IO并在操作完成时调用pthread_cond_signalsem_post。或者,如果您能承担一点性能成本,甚至可以通过管道或socketpair将刚刚读取的数据转发回自己,并使用selectpoll在主线程中异步读取常规文件,就像处理套接字/管道/ ttys一样。


3
尽管我不太喜欢POSIX aio,但它仍然比每个操作都启动一个线程要好得多,这种方式太过浪费资源。可以说是把孩子和洗澡水一起倒掉了。 - Ben Voigt
2
不是每个操作都需要。对于许多用途,每个文件一个线程就足够了。如果您需要同时在同一文件上进行多个读/写操作,则每个“用户”文件一个线程(而不是每个访问)仍应该足够。glibc的AIO实现类似于这样; 它只是在其上放置了可怕的POSIX AIO API,而不是给您自由制定良好的API。 - R.. GitHub STOP HELPING ICE
4
在普通文件上,select 命令是无用的。它总是表示这些文件可以进行读写操作。这不是设计缺陷;即使 select 命令只在可以立即从缓存中读取数据(或在可用空闲缓存内存时可以写入)时显示它们是可读的(或可写的),也会存在竞争条件 - 在 select 返回后,缓存可用性状态可能会发生变化,并且在内核空间中 read/write 命令可能会进入睡眠状态。当然,另一种替代方案是对要访问的文件部分进行 mmapmlock(如果要写入,则还需 fallocate),然后使用普通 IO。 - R.. GitHub STOP HELPING ICE
1
@R:但是mmapmlock是阻塞的,我不认为有这些系统调用的任何异步版本。 - Ben Voigt
4
如果文件位于慢速媒体上(例如划痕的光盘或NFS),正常阅读它们可能会导致程序长时间冻结。对于处理单个线程中的多个客户端的交互应用程序或服务器,这可能是无法接受的。使用专用线程(甚至是单独的进程)来执行锁定可以解决mmap和mlock在内核空间中睡眠的问题(如果一个共享映射被一个进程锁定,则其他映射它的进程应始终将其换入)。 - R.. GitHub STOP HELPING ICE
显示剩余2条评论

21

异步I/O。

实时信号是内核通知系统I/O操作完成的机制。

struct aiocb 将异步I/O请求和信号号码联系起来。


请注意,这并不意味着这是一个好的做事方式。请参考我的回答。 - R.. GitHub STOP HELPING ICE
因此,实时信号不应该由普通用户使用(我指发送和||处理实时信号)。 - Bionix1441

5

这是一个老问题,但仍然存在。

Linux中的glibc(NPTL)使用两个实时信号来实现POSIX线程。它们对用户隐藏(通过调整最小/最大数量常量)。所有需要将库调用传播到所有线程的事件(例如setuid)都通过这些信号完成:调用线程发送信号以将更改应用于所有线程,等待确认并继续执行。


-2

使用实时信号的其他原因是有一些应用程序需要与各种外部设备进行交互,而这些交互方式是通过多种手段实现的(串口IO,甚至是直接寻址某些比你认识的大多数人都要老的卡)。这就是所谓的“实时”应用程序——它与真实世界以真实世界的时间进行交互,而不是以“计算机时间”进行交互。

它的许多功能都在一个守护进程中,该进程处于主循环中:处理事件、读取信息、将结果写入串口、将事物存储在数据库中等等,然后循环处理下一个事件。机器上的其他进程(用户进程)从数据库中读取信息、显示信息等等。这些其他进程中的用户可以向守护进程发送各种信号,以通知它各种条件:停止、更改输入数据等等。例如,用户进程发送一个“停止”信号,守护进程的信号处理程序只需两行代码,设置一个标志变量。当守护进程有机会并且方便时,它就会停止。这个“中断”代码非常简单、快速和非侵入性。但它达到了目的,不需要复杂的IPC结构,并且运行得非常好。

是的,在实时应用程序中,这些信号有其存在的原因。如果得到适当处理,它们可以正常工作,谢谢。


请注意,该问题并不是关于信号的一般性问题,而是关于POSIX“实时”信号的问题。您提到的“停止”信号可能是普通信号,而不是实时信号。 - Alex D
停止只是该应用程序使用的信号之一。正如我所指出的,其他信号被用于实时发出“数据准备就绪”和其他条件的信号。 - CLWill
6
明白了,但我仍然觉得这个回答与提问者的问题无关。重点不在于这些信号是否被“实时”使用,而在于它们是否属于一类特殊的信号,称为“POSIX实时信号”。这些信号不同于普通信号,它们永远不会合并,保证按照它们引发的顺序传递,并且还可以附带一个额外的参数(不仅仅是信号编号)。如果用于控制你的守护程序的信号属于这种类型,那么你可以解释一下原因。这就是问题所在。 - Alex D
OP问了使用案例是什么。我给出了一个使用案例。QED - CLWill

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接