如果我运行这些命令:
dmesg | head -n 10
Run Code Online (Sandbox Code Playgroud)
我认为操作系统发送回某种信号,dmesg一旦head读取了 10 行。这是如何运作的?这是什么head告诉内核?
这与程序终止不同,因为这是正常的“干净”停止。
cuo*_*glm 28
这取决于操作系统缓冲区和 .10 次和 11 次写入之间的时间dmesg。
后head写10行,它终止,dmesg会收到SIGPIPE信号,如果继续写入管道。
根据您的操作系统缓冲区,dmesg在使用head它们之前通常会写入 10 多行。
要查看head已消耗超过 10 行的内容,您可以使用:
strace -f sh -c 'dmesg | head -n 10'
Run Code Online (Sandbox Code Playgroud)
(看head进程,数read系统调用数。)
查看写入速度效果如何:
strace -f sh -c "perl -le '$|++;print 1 while 1' | head -n 10"
Run Code Online (Sandbox Code Playgroud)
小智 17
write()如果出现以下情况,该功能将失败:... 尝试写入未打开供任何进程读取或仅打开一端的管道或 FIFO。SIGPIPE 信号也应发送到线程。
所以事件的顺序是:
该head过程出来。这会导致其所有打开的文件描述符都被关闭,包括其标准输入,即管道的一端。
该dmesg进程调用write()其标准输出,即管道的另一端。
这会导致 SIGPIPE 被传送到dmesg进程。
dmesg 对 SIGPIPE 没有特殊处理,因此应用默认操作,即终止进程。
您可以通过更改 SIGPIPE 信号的操作来对此进行试验。例如,此管道在打印一行后终止:
$ yes | head -1
y
$
Run Code Online (Sandbox Code Playgroud)
但如果您忽略 SIGPIPE,则它不会终止:
$ trap '' PIPE
$ yes | head -1
y
Run Code Online (Sandbox Code Playgroud)
此时,yes进程仍在尝试写入管道,但 EPIPE 写入失败。