Теперь, чтобы узнать, как получить код завершения процесса, порожденного ветвлением, напишем простую программу, выполняющую ветвление: сценарий в примере 5.17 порождает дочерние процессы и выводит коды их завершения, возвращаемые функцией os.wait, пока не будет нажата клавиша q”.
Пример 5.17. PP4E\System\Exits\testexit_fork.py
порождает дочерние процессы и получает коды их завершения вызовом функции os.wait; прием ветвления может использоваться в Unix и Cygwin, но он не работает в стандартной версии Python 3.1 для Windows;
примечание: порождаемые потоки выполнения совместно используют глобальные переменные, но каждый процесс имеет собственные копии этих переменных (однако при ветвлении процессов файловые дескрипторы используются совместно) —exitstat здесь всегда имеет одно и то же значение, но может отличаться в случае использования потоков;
import os
exitstat = 0
def child(): # здесь можно вызвать os.exit для завершения
global exitstat # изменит глобальную переменную этого процесса
exitstat += 1 # код завершения для функции wait родителя
print(‘Hello from child’, os.getpid(), exitstat) os._exit(exitstat) print(‘never reached’)
def parent():
while True:
newpid = os.fork() # запустить новую копию процесса
if newpid == 0: # если это копия, вызвать функцию child
child() # ждать ввода ‘q’ с консоли
else:
pid, status = os.wait()
print(‘Parent got’, pid, status, (status >> 8)) if input() == ‘q’: break
if __name__ == ‘__main__’: parent()
Если запустить эту программу в Linux, Unix или Cygwin (не забывайте, что функция fork не работает в стандартной версии Python для Windows, — по крайней мере, когда я работал над четвертым изданием этой книги), она выведет следующие результаты:
[C:\…\PP4E\System\Exits]$ python testexit_fork.py
Hello from child 5828 1
Parent got 5828 256 1
Hello from child 9540 1
Parent got 9540 256 1
Hello from child 3152 1
Parent got 3152 256 1 q
Если внимательно изучить этот вывод, можно заметить, что код завершения (последнее выводимое число) всегда одинаков — 1. Поскольку ответвленные процессы начинают жизнь как копии создавших их процессов, они также получают копию глобальной памяти. Поэтому каждый дочерний процесс получает и изменяет собственную глобальную переменную exitstat, не трогая экземпляров этой переменной в других процессах. В то же время дочерние процессы получают копии файловых дескрипторов, которые используются совместно с родительским процессом, и именно поэтому вывод от дочерних процессов попадает в то же самое место.
Использованная литература:
Марк Лутц — Программирование на Python, 4-е издание, I том, 2011