Engineering Note

プログラミングなどの技術的なメモ

Python プロセスAPIの操作(fork, exec, wait)

api

Pythonでは、osモジュールによりUnixLinuxで扱われるプロセスに纏わる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

 

問題なく子プロセスが終了したことが確認できました。

 

参考書籍

ふつうのLinuxプログラミング 第2版 Linuxの仕組みから学べるgccプログラミングの王道