Давайте начнем с определения первичного заблуждения здесь:
Как видно из вывода, Hello из Parent печатается, когда fork () возвращает 0. Итак, из моего понимания Hello from Parent былофактически печатается дочерним процессом
Дочерний и родительский процессы - это два отдельных процесса, выполняющихся одновременно.Порядок этих двух выходных данных не является четко определенным, зависит от вашего ядра и других соображений синхронизации и не связан с тем фактом, что ваш код содержит блок if / else, записанный так, как он у вас. 1
Давайте перепишем ваш код в виде линейного потока «инструкций» в абстрактном смысле:
0: Function foo():
1: Invoke system call fork(), no arguments, store result to $1
2: If $1 is non-zero, jump to label #1.
3: Invoke C function printf(), argument "Hello from Child!"
4: Jump to label #2.
5: Label #1:
6: Invoke C function printf(), argument "Hello from Parent!"
7: Label #2:
8: return control to calling function.
Как только ваша программа достигнет 1:
, системный вызов вызывается,передача управления ядру.Ядро дублирует процесс, помещает PID дочернего элемента в возвращаемое значение fork
в родительском процессе и помещает 0
в возвращаемое значение fork
в дочернем процессе.На x86 возвращаемое значение сохраняется в регистре eax
(rax
для x64) как часть соглашения о вызовах системного вызова.
Один из этих двух процессов в конечном итоге будет запланирован для запуска ядром.В вашем случае дочерний процесс оказался первым запланированным.Ваш код пользовательского режима вернул управление из режима ядра, прочитал возвращаемое значение (из eax / rax, если на x86), которое было нулевым, и не перешел на метку # 1.Он напечатал Hello from Child!
, а затем вернулся из функции (к вызывающей стороне foo
, так как дочерний элемент получил копию стека родителя).
То же самое произошло с родителем, за исключением того, что родитель получилненулевое значение возвращается из системного вызова и печатается Hello from Parent!
.Он был запущен по расписанию, и ваш код пользовательского режима получил управление от ядра в тот же момент, только с другим значением, возвращаемым системным вызовом.
1 Возможно также, чтодва выходных сигнала могут каким-то образом чередоваться, но это не так актуально для этого обсуждения и требует понимания того, как процессы Linux выполняют ввод / вывод.