Pythonでは、osモジュールによりUnixやLinuxで扱われるプロセスに纏わるAPIを利用することができます。
今回はfork、exec、waitの基本的な使い方について学んでいきます。
forkとは
forkは、自プロセスのコピーを作成するシステムコールで、元のプログラムを親プロセス、新しく作成されたコピーを子プロセスと言います。
pythonでは、以下でプロセスをフォークさせます。
os.fork()
fork()
の戻り値に関しては、親プロセスでは子プロセスのPIDとなり、子プロセスでは0となります。
なお、forkはUnix/Linux環境でないと利用できません。
execとは
execは、自プロセスを完全に上書きし、新しいプログラムに置換し実行します。
exec*関数は、いくつかの末尾の異なる関数がありますが、今回はexecl()
を使用しました。
なお、execve()
はシステムコールで、他はライブラリ関数となります。
os.execl(path, arg0, arg1, ...)
なお、execはUnix/Linux環境でないと利用できません。
waitとは
waitは、forkした子プロセスの実行完了を待機します。
今回は以下のwaitpid()
で子プロセスのPIDを指定し、親プロセス側で子プロセスの終了を待機します。
os.waitpid(pid, options)
waitpid()
では、子プロセスのPIDとステータスがタプルで返ってきます。
スクリプトの作成
それでは上記APIを利用したプログラムを作成します。
コードの内容は、ふつうのLinuxプログラミングに記載されているものを参考として、子プロセスでシェルを起動させ、親プロセスで子プロセスの終了を待機させます。
# test.py import os import sys try: pid = os.fork() except OSError as e: print("fork():{}".format(e)) sys.exit(1) if not pid: try: os.execl("/bin/sh", "/bin/sh") os._exit(0) except OSError as e: print("execl():{}".format(e)) sys.exit(1) else: try: status = os.waitpid(pid, 0)[1] except OSError as e: print("waitpid():{}".format(e)) sys.exit(1) print("child (PID={}) finished: ".format(pid), end="") if os.WIFEXITED(status): print("exit, status={}".format(os.WEXITSTATUS(status))) elif os.WIFSIGNALED(status): print("signal, sig={}".format(os.WTERMSIG(status))) else: print("abnormal exit")
動作確認
それでは、上記で作成したスクリプトを実行してみます。
$ python3 test.py # whoami root # exit child (PID=72) finished: exit, status=0
問題なく子プロセスが終了したことが確認できました。