![管道、shell 脚本和 ulimit](https://linux22.com/image/1281252/%E7%AE%A1%E9%81%93%E3%80%81shell%20%E8%84%9A%E6%9C%AC%E5%92%8C%20ulimit.png)
我有一个从代码调用的命令:
execvp('generate', ...)
这是一个可执行程序,我的代码通过 stdin、stdout 和 stderr 与之通信。它运行正常,没有任何问题。
我想改变这一点,以便我可以设置资源限制generate
。所以我尝试调用:
ulimit -t 1 && generate
但当我尝试与它通信时,发现管道断了。
因此我将上面这一行放入了 shell 脚本中generate_wrapper
:
#!/bin/bash
ulimit -t 1 && generate
当我尝试与它通信时,发现管道破裂了。
但
$ echo "foo" | generate_wrapper
$ echo "foo" | generate
两者都给出了正确的、相同的输出。我想可能是 &&,所以我只尝试了简单的命令:
#!/bin/bash
generate
但是它仍然可以从 CL 运行,并且当我尝试通过代码与它通信时仍然会遇到管道损坏的情况。
我尝试明确地路由 fds,并得到:
#!/bin/bash
generate >&1 2>&2 <&0
但是不,当我尝试通过代码与它通信时,仍然会遇到管道损坏的情况。
显然我不知道自己在做什么。你能帮忙吗?我该如何编写包装器,以便可以ulimit
生成子进程(rlimit
在我的宿主语言中不适用于 pid)并仍与其通信?
答案1
您之前不想调用ulimit (2)
生成代码的原因是什么execvp
?
从手册页中:
概要
#包括 <ulimit.h>
长 限制(int cmd,...);描述
ulimit() 函数将获取并设置进程限制。
答案2
EPIPE
当SIGPIPE
信号设置为忽略并且写入过程尝试将进一步的输出写入管道已关闭的读取端时,会引发“管道破裂”错误消息,在您的情况下,generate
所有引用其标准输入的文件描述符都已关闭。
如果有一个父进程已将SIGPIPE
信号设置为忽略,则子进程将继承此行为(...并且在非交互式 shell 中这无法撤消)。
因此,就您而言,调用generate
可执行文件的程序已将信号设置SIGPIPE
为忽略。然后,当您的generate
程序generate_wrapper
处理输入一秒钟后 ( ulimit -t 1
)generate
将退出并关闭其标准输入。如果您的写入过程忽略了该信号 SIGPIPE
,则尝试将更多数据写入系统调用现已关闭的标准输入generate
将write
失败,并且您将看到EPIPE
其“管道损坏”错误消息(请参阅man 2 write
)。
至于减少 CPU 资源消耗的包装器,请使用以下工具流或者缓冲存储器。
# test: ulimit -t
#help ulimit
{
time -p bash -c 'yes | head -100000000 | wc -c'
echo
time -p bash -c 'ulimit -t 1; yes | head -100000000 | wc -c'
}
# cstream test
#top -u
yes | cstream -b 100000 -t 100000 -o -
yes | cstream -b 100000 -t 100000 | cat -n
# generate_wrapper
#!/bin/bash
cstream -b 100000 -t 100000 | generate
答案3
execvp 不处理系统命令,只处理直接二进制文件。同样,脚本文件也只是以这种方式屏蔽的系统命令。
我认为如果您希望运行命令而不是二进制文件,则需要使用 system()。
dmckee 关于在 execvp() 之前调用 ulimit() 的想法也是合理的。但是,这将影响进程从现在开始执行的所有操作。