На эту тему можно сказать немало, некоторые из которых могут уместиться в ответе, а большая часть требует дальнейшего чтения.
Для Q1 , я бы сказал концептуально да, но задания не являются автоматическими, а отслеживание и контроль заданий не являются волшебными. Я не вижу никакой логики в фрагментах кода, которые вы показываете, например. устанавливает и поддерживает таблицу заданий. Я понимаю, что это всего лишь пример, поэтому, возможно, логика управления работой в другом месте. Управление заданиями является функцией общих существующих оболочек Unix, но если человек пишет новую оболочку Unix с нуля, необходимо добавить функции управления заданиями в виде кода / логики.
Для Q2 , то, как вы это выразили, совсем не так, как я бы сказал. После первого вызова fork()
, да, есть p1 и c1, но следует признать, что сначала p1 и c1 являются различными экземплярами одной и той же программы (shellex
); * только после вызова execve()
работает exampleProgram
. fork()
создает дочерний экземпляр shellex
, а execve()
вызывает замену дочернего экземпляра shellex
(в оперативной памяти) на exampleProgram
(при условии, что это значение argv[0]
).
Нет никакого реального смысла в том, чтобы родитель "казнил" ребенка, ни процесс, который заменяет ребенка после execve()
, кроме как просто заставить его работать. Родитель запускает дочерний процесс и может ждать завершения дочернего выполнения, но на самом деле родительский процесс и вся его иерархия дочерних процессов выполняют каждый самостоятельно, будучи выполненными ядро.
Но да, если сказано, что запускаемая программа должна запускаться в фоновом режиме, то shellex
примет дальнейший ввод, и при следующем вызове fork()
будет родитель shellex
с двумя дочерними элементами. процессы. И снова, сначала дочерний c2 будет экземпляром shellex
, быстро замененным на execve()
любой программой, которая была названа.
(Относительно работы в фоновом режиме, будет ли &
иметь такой эффект, зависит от логики внутри функции с именем parseline()
в примере кода. Оболочки, с которыми я знаком, используют &
, чтобы сказать «запустите это» на заднем плане ", но в этом нет ничего особенного или волшебного. Недавно написанная оболочка Unix может сделать это каким-то другим способом, с завершающим +
, или ведущим BG:
, или с чем угодно, что решит автор оболочки. .
Для Q3 и Q4 первое, что нужно распознать, это то, что родитель, которого вы вызываете p1
, является программой оболочки, которую вы показали , Так что, нет, p1
не будет частью работы.
В Unix задание - это набор процессов, которые выполняются как часть одного конвейера. Таким образом, работа может состоять из одного процесса или нескольких. Такие процессы остаются подключенными к терминалу, из которого они выполняются, но могут находиться на переднем плане (работающем и интерактивном), приостановленном или на заднем плане (работающем, не интерактивном).
one process, foreground : ls -lR
one process, background : ls -lR &
one process, background : ls -lR, then CTRL-Z, then bg
many processes, foreground : ls -lR | grep perl | sed 's/^.*\.//'
many processes, background : ls -lR | grep perl | sed 's/^.*\.//' &
Чтобы эмпирически увидеть задания и процессы, запустите конвейер в фоновом режиме (5-й из 5 приведенных выше примеров) и во время его работы используйте ps
, чтобы показать вам идентификаторы процессов и идентификаторы группы процессов. например, на моей версии bash для моего Mac это:
$ ls -lR | grep perl | sed 's/^.*\.//' &
[1] 2454 <-- job 1, PID of the sed is 2454
$ ps -o command,pid,pgid
COMMAND PID PGID
vim 2450 2450 <-- running in a different tab
ls -lR 2452 2452 }
grep perl 2453 2452 }-- 3 PIDs, 1 PGID
sed s/^.*\.// 2454 2452 }
В отличие от этого прикрепления к оболочке и терминалу, демон отсоединяется от обоих. При запуске демона родитель использует fork()
для запуска дочернего процесса, но затем завершает работу, оставляя только дочерний процесс, и теперь с родителем PID 1. Ребенок закрывается stdin
, stdout
и stderr
, поскольку это бессмысленно, так как демон работает "без головы".
Но в оболочке родительский объект (который, опять же, является оболочкой) продолжает работать либо wait()
ing (дочерняя программа переднего плана), либо не wait()
ing (фоновая дочерняя программа), а дочерний процесс обычно сохраняет использование stdin
, stdout
и stderr
(хотя они могут быть перенаправлены в файлы и т. д.)
И оболочка может вызывать вложенные оболочки, и, конечно, любая запускаемая программа может fork()
иметь свои собственные дочерние процессы и так далее. Так что иерархия процессов может стать довольно глубокой. В противном случае без специальных действий дочерний процесс будет находиться в той же группе процессов, что и его родитель.
Вот несколько статей для дальнейшего чтения:
В чем разница между заданием и процессом в Unix?
https://unix.stackexchange.com/questions/4214/what-is-the-difference-between-a-job-and-a-process
https://unix.stackexchange.com/questions/363126/why-is-process-not-part-of-expected-process-group
Справочное руководство Bash; Job Control
Справочное руководство Bash; Основы управления заданиями