对于我正在编写的脚本来说,正确处理失败非常重要fork()
(请参阅https://rachelbythebay.com/w/2014/08/19/fork/寻找为什么)。
但是,如何在不使我的系统因进程而崩溃的情况下,可靠地使fork()
测试我的错误例程失败?
我尝试了这样的事情:
#!/bin/bash
set -x
whoami
number_of_processes=$(ps auxf | wc -l)
number_of_processes_plus=$((number_of_processes+480))
echo "found $number_of_processes processes, setting the limit to $number_of_processes_plus"
ulimit -u $number_of_processes_plus
perl -e '
use strict;
use warnings;
my $pid = fork();
my $errno = $!;
print "ERRNO: $errno\n";
if($pid == -1) {
warn "PID was -1!!! errno: >>>$errno<<<\n";
} else {
if(defined $pid) {
if($pid == 0) {
warn "Child-process\n";
} else {
warn "Parent-process\n";
}
} else {
warn "\$pid NOT DEFINED";
}
}
'
从我认为对此的理解来看,这应该获取进程数(通过ps auxf | wc -l
)并设置ulimit -u
为该数 + 480。480 只是通过反复尝试直到 perl 进程启动而得出的。如果我将其设置为低于 480,则只会得到
forkfail.sh: fork: retry: Die Ressource ist zur Zeit nicht verfügbar
forkfail.sh: fork: retry: Die Ressource ist zur Zeit nicht verfügbar
forkfail.sh: fork: retry: Die Ressource ist zur Zeit nicht verfügbar
...
(资源不可用。)
如果我将其设置为远高于 +480,它总是可以工作。如果设置为 480,它有时可以工作,有时则不行。但我似乎无法让它可靠地失败。
如何做到这一点而不产生系统允许的那么多进程,从而导致系统无法使用?
答案1
systemd
在许多 Linux 系统上,您可以使用基于 cgroup通过 systemd 的服务属性进行任务限制TasksMax=
,可以精确针对一个特定的命令:
$ systemd-run --user --collect --pty -p TasksMax=1 /bin/sh sh-5.1$ ls sh:fork:重试:资源暂时不可用
限制
ulimit -u
仅统计由你的 UID,因此a
中的标志ps auxf
没有多大意义。但除此之外,在 Linux 上,它实际上不计算进程,而是计算任务– 可以是独立进程,也可以是线程。
$ man 2 setrlimit 限制NPROC 这是对现存进程数量的限制(或者更多 在 Linux 上,线程)是调用者的真实用户 ID 过程。只要当前属于 该进程的真实用户 ID 大于或等于此 限制,fork(2)失败并出现错误 EAGAIN。
(随着 Linux NPTL 实现线程的方式,它们已经成为主要的对象类型——进程只是“线程组领导者”,而 PID 实际上是“线程组 ID”。)
现在,your_processes + your_threads
(正确计数)和your_processes + other_uid_processes
(您正在使用的计数)之间的差异恰好约为 480。
要ps
包含线程,请使用H
选项。(或者-L
选项。或者-T
选项。)
n=$(ps uxH | wc -l)
n=$((n - 4))
# Discount the $() subshell process; the 'ps' process;
# the 'wc' process; and the ps header line, for a total of 4. Usually.
ulimit -n $n
或者,由于限制是基于 UID 的,如果您习惯在专用 UID 下启动测试脚本(该 UID 尚未运行其他进程),则更可靠sudo
。您甚至可以使用包装器调用 setuid() 为每次运行随机选择一个新的 UID(从与实际帐户不对应的范围内)。
这样做可以避免竞争条件,即在您的调用和实际测试脚本之间任务数量发生显着变化ps
(例如,由于后台 cronjobs 启动/完成,或者由于浏览器唤醒某些选项卡并暂停其他选项卡)。
$ sudo -u nobody sh -c "(ulimit -u 4; ps xH)"
PID TTY STAT TIME COMMAND
1686939 pts/1 S+ 0:00 sh -c (ulimit -u 4; ps xH)
1686940 pts/1 S+ 0:00 sh -c (ulimit -u 4; ps xH)
1686941 pts/1 R+ 0:00 ps xH
$ sudo -u nobody sh -c "(ulimit -u 3; ps xH)"
sh: fork: retry: Resource temporarily unavailable