Совместное использование вызовов ехес и fork
Системные вызовы fork и ехес, объединенные вместе, представляют мощный инструмент для программиста. Благодаря ветвлению при использовании вызова ехес во вновь созданном дочернем процессе программа может выполнять другую программу в дочернем процессе, не стирая себя из памяти. Следующий пример показывает, как это можно сделать. В нем мы также представим простую процедуру обработки ошибок fatal и системный вызов wait. Системный вызов wait, описанный ниже, заставляет процесс ожидать завершения работы дочернего процесса.
(* Программа runls3 - выполнить ls как субпроцесс *)
uses linux,stdio;
var
pid:longint;
begin
pid := fork;
case pid of
-1:
fatal ('Ошибка вызова fork');
0:
begin
(* Потомок вызывает exec *)
execl('/bin/ls -l');
fatal('Ошибка вызова exec ');
end;
else
begin
(* Родительский процесс вызывает wait для приостановки
* работы до завершения дочернего процесса.
*)
wait(nil);
writeln('Программа ls завершилась');
halt(0);
end;
end;
end.
Процедура fatal использует функцию perror для вывода сообщения, а затем завершает работу процесса. Процедура fatal реализована следующим образом:
procedure fatal(s:pchar);
begin
perror(s);
halt(1);
end;
Снова графическое представление, в данном случае рис. 5.4, используется для наглядного объяснения работы программы. Рисунок разбит на три части: До вызова fork, После вызова fork и После вызова ехес.
В начальном состоянии, До вызова fork, существует единственный процесс А
и программный счетчик
PC направлен на оператор fork, показывая, что это следующий оператор, который должен быть выполнен.
После вызова fork существует два процесса, А
и В. Родительский процесс A выполняет системный вызов wait. Это приведет к приостановке выполнения процесса А до тех пор, пока процесс В не завершится. В это время процесс В использует вызов execl для запуска на выполнение команды ls.
pid:=fork; | < PC | ||||||||
A | |||||||||
До вызова fork | |||||||||
wait(nil); | < PC | ||||||||
execl('/bin/ls -l'); | < PC | ||||||||
A | B | ||||||||
После вызова fork | |||||||||
После вызова exec | |||||||||
(* 1-ая строка ls*) | < PC | ||||||||
wait(nil); | < PC | ||||||||
A | B (теперь | ||||||||
выполняет команду ls) |
Рис. 5.4. Совместное использование вызовов fork и ехес
Что происходит дальше, показано в части После вызова ехес на рис. 5.4. Процесс В
изменился и теперь выполняет программу ls. Программный счетчик процесса В установлен на первый оператор команды ls. Так как процесс А
ожидает завершения процесса В, то положение его программного счетчика PC не изменилось.
Теперь можно увидеть в общих чертах механизмы, используемые командным интерпретатором. Например, при обычном выполнении команды оболочка использует вызовы fork, ехес и wait приведенным выше образом. При фоновом исполнении команды вызов wait пропускается, и оба процесса – команда и оболочка – продолжают выполняться одновременно.