what_me: Стиль вызова fork
Все знают, что при вызове системных функций необходимо проверять был ли вызов успешен. Обычно при успешном вызове фуцнкции возвращают true, а при неудаче false, и вызовы оформляются в стиле "сделай или умри":
mkdir "Новая
папка(2)" or
die "Can't mkdir:
$!";
В случае с fork так написать не получается, потому что при успехе для ребенка она возвращает 0, который нужно отличать от undef возвращаемого при неудаче. Приходится писать уродливые конструкции из if(...){...} elsif(...){...} else{...};. Так писать мне не нравится, потому что трудно обосновать выбор что в первом условии проверять, что во втором, а что оставить без проверки на третий блок. Сейчас обкатываю такой вариант записи:
#!/usr/bin/perl -l --
use strict;
use warnings;
defined (
my $pid =
fork ) or
die "Can't fork:
$!";
if ($pid) {
print
"parent"
}
else {
print
"child";
}
Update: Все таки да, так будет лучше:
my $pid =
fork;
die "Can't fork:
$!" unless
defined $pid;
Для случаев когда форков много или код используется во многих местах удобно оформить вызов внутри процедуры
Три варианта:
1) Вставить die unless defined $pid между fork и if
2) sub myfork { my $pid = fork; die unless defined $pid; return $pid; }
3) sub myfork { my ($parent, $child) = @_; my $pid = fork; die unless defined $pid; $pid ? &$child() : &$parent($pid); }
И если при неудачном форке мы хотели бы иметь возможность не умирая повторить попытку, то вот пример
Важно проверять причину ошибки при форке. Так, например, получив ошибку EAGAIN (нехватка ресурсов), можно решить проблему и повторить вызов fork.
Записать можно разными способами, зависит от архитектуры программы. В общем и самом нагладном случае примерно так:
use Errno qw(EAGAIN);
FORK: {
if (my $pid = fork) {
say "parent";
} elsif (defined $pid) {
say "child";
} elsif ($! == $EAGAIN) {
# solve problem
redo FORK;
} else {
die "Can't fork: $!";
}
}