- ベストアンサー
プロセスIDの取得方法
Unix C++でプロセスIDの取得方法を教えてください。 (見当違いの質問だったらすみません) 親プロセス(自分)のプロセスIDと、親プロセスの起動した子プロセスのプロセスIDを取得したいです。 また、親プロセスの起動した子プロセスのプロセスIDを使って親プロセス終了時に子プロセスをkillしたいと思うのですが、 具体的にどうすればいいかわからず困っています。
- みんなの回答 (6)
- 専門家の回答
質問者が選んだベストアンサー
プロセスを殺す処理は kill() を使いましょう、と toysmith さんが 書いてましたね。 kill(pid_c, SIGTERM); です。 補足で「sig_handler とは?」とありますが、それはシグナルを処理する 為に書いた関数の名前です(関数名は何でもいい)。 一度、シグナルの処理をしてしまうと、初期状態に戻されてしまうので、 sig_handler() の中でも、signal() を使って、再登録しています。
その他の回答 (5)
- a-kuma
- ベストアンサー率50% (1122/2211)
toysmith> 多数の子プロセスを生成した場合、単一の子プロセスを狙い撃ちで里子に出すことが出来ません 親プロセスで SIGCHLD を無視するのは、「細かいことは知らんよ」という場合に 限って、とした方が良いでしょう。 一般的には、親プロセスで SIGCHLD を捕捉して、wait() をする、というかたちを とります。 一番おおざっぱな形は以下のような感じ。 void sig_handler(int sig) { wait(NULL); signal(SIGCHLD, sig_handler); } int main(void) { signal(SIGCHLD, sig_handler); ... } もし、私がやるとしたら wait() よりも waitpid() を使うかな。 捕捉するシグナルが(親自身も含めて)ひとつとは限らないから、シグナルハンドラを ひとつにしておいて int sig_handler(int sig) { if (sig == SIGCHLD) { int stat; while (waitpid(-1, &stat, WNOHANG) > 0) { /* stat 次第では、何か処理が有るかも */ } } signal(sig, sig_handler); } ってな感じ。
補足
非常に申し訳ありません。a-kumaさん、toysmithさん。 いまだによくわかりません。 言いたいことはわかる気がするのですが、どういうふうにプログラムを組めばよいのか・・・。 =============================== void sig_handler(int sig) { wait(NULL); signal(SIGCHLD, sig_handler); /* sig_handlerとは? */ } int main(void) { signal(SIGCHLD, sig_handler); ... pid_t pid_c; pid_c = fork(); if(pid_c == 0) { execl("aa", NULL); } else if (pid_c < 0) { } ・・・・ /* プロセスを殺す処理? */ } ======================= 上記のようなプログラムになるのでしょうか? 子プロセスを殺す処理はどうなるのでしょうか? ちなみに子プロセスはシェルです。 質問ばかりで申し訳ありません。よろしくお願い致します。
- toysmith
- ベストアンサー率37% (570/1525)
unix系なら「お行儀良い終了要求」としてSIGTERMが用意されているので子プロセス(fork(2)だと生成されるのはスレッドではなくプロセス)でSIGTERMをトラップ(signal(2))してexit(2)した方が良いでしょう。 <defunct>はいわゆる「ゾンビ-プロセス」で、死にぞこなった状態です。 unixでは「親は子を産んだら死ぬまで面倒を目る」という決まりがあります。 子の死んだときの面倒(死に水を取るようなもの)の見方は… wait(2)で子プロセスの終了を待つだけです。 親プロセスと子プロセスが同時に実行しなければいけない場合、安易にwait(2)すると親プロセスが止まって(=子プロセスの終了待ち)しまいます。 この場合は子プロセスをinitプロセスに里子に出すことでゾンビー化を回避できます。 initは全てのプロセスの先祖であり、全ての親無しプロセスを養子として迎え入れます。 子プロセスをinitに里子に出す方法はsignal(2)でSIGCHLDを無視するように設定ます。 ただ、子の方法にも問題があります。 多数の子プロセスを生成した場合、単一の子プロセスを狙い撃ちで里子に出すことが出来ません。 この場合は少々ややこしい制御が必要になります。 シェルで実現しているので不可能ではありませんが…。
補足
>親プロセスと子プロセスが同時に実行しなければいけない場合、安易にwait(2)すると親プロセスが止まって(=子プロセスの終了待ち)しまいます。 >この場合は子プロセスをinitプロセスに里子に出すことでゾンビー化を回避できます。 > initは全てのプロセスの先祖であり、全ての親無しプロセスを養子として迎え入れます。 >子プロセスをinitに里子に出す方法はsignal(2)でSIGCHLDを無視するように設定ます。 >ただ、子の方法にも問題があります。 >多数の子プロセスを生成した場合、単一の子プロセスを狙い撃ちで里子に出すことが出来ません。 >この場合は少々ややこしい制御が必要になります。 >シェルで実現しているので不可能ではありませんが…。 申し訳ありません。 プログラムは具体的にどうなるのでしょうか。 ご教授ください。
- toysmith
- ベストアンサー率37% (570/1525)
以下、unixという言葉はunix系OS(unix version 6~9,SystemIII/V、全てのBSD及びXENIXを含むベンダー系UNIX)とunixもどきOS(minix,linux,xinuなど)の共通部分を指しています。 OS固有の拡張によって実現可能な場合があるかもしれません。 「まったく関係ないプロセスのプロセスID」を取得する事は(一般的な方法としては)ありません。 unixはPIDでプロセスを認識する為、他の方法では一意にプロセスを特定するとこが出来ません。 unixには「プロセス名」という概念は無く、しいて言えば実行ファイル(=実行権を持ったスクリプトを含む)の名称がプロセス名とされます。 よって、1コマンドが多重に起動された場合は全てのコマンドが同じプロセス名となるため一意に認識できません。 繰り返しますが、プロセスを一意に特定する為のキーはPIDのみです。 a-kumaさんがおっしゃるようにOSの持つプロセス管理テーブルを参照する事である条件下(プロセスを多重起動しない)でのみ一意性が産まれます。 ただし、unixはマルチユーザ、マルチタスクである為、この方法には確実ではありません。 確実でない事を覚悟の上ならa-kumaさんのおっしゃる方法でPIDの取得は可能でしょう。 cm = popen("ps -e | awk '/inetd/{print $1}'", "r"); の方が効率はいいでしょう。 プロセス起動(fork(2)とexec(2))はシステムコールの中でも最も非効率です。 移植性が無くなってもよいなら/dev/kmemをオープンしてプロセス管理テーブルを直接読み込む方法もあります。 /dev/kmemはunixカーネルが管理するメモリ領域そのもので、ここを読めば全ての管理情報が取得可能です。 psもここを読んで表示しているので結果としては同じになります。 ただし、/dev/kmemのフォーマットはOSごとに(下手をするとバージョンごとに)違いますのでkmem.h参照してプロセス管理テーブルの位置とフォーマットを調べる必要があります。 kmem.hは/usr/include/sysか/usr/include/hardwareにある事が多いのですが、これもOSによって違いがありますので御確認下さい。
補足
プロセス名でなんとかなるのかなあって思っていたのですが、確かにプロセス名だと、複数いたときどうする?っていう問題がありますね。 ところで、以下のように子スレッドを起動したとき、子スレッドをkillするにはどうしたらいいのでしょうか。kill(pid_c,SIGINT)ではできませんか? ======================= pid_t pid_c; pid_c = fork(); if(pid_c == 0) { execl("aa", NULL); } else if (pid_c < 0) { return -100; } ================================= また、ここで起動した子スレッドのaaなんですが、 psでみると、<defunct>となっています。 これはどうしてですか? 回避策はあるのでしょうか。
- a-kuma
- ベストアンサー率50% (1122/2211)
> 親とか、子のプロセスでなく、まったく関係ないプロセスのプロセスIDをとることは可能ですか?? 全く関係ないプロセスをどうやって特定しますか? 例えば、プロセス名が分かっているとしたら、一番汎用的なのは ps コマンドを 使うことです。例えば、inetd のプロセスIDを取得する場合、 FILE *cm; int pid; cm = popen("ps -e | grep inetd | awk '{print $1}'", "r"); fscanf(cm, "%d", &pid); ってな感じ。 後は、どんな unix でも、ってわけにはいかないのですが、プロセスファイル システムを使う手もあります。man proc を参照して下さい。
- toysmith
- ベストアンサー率37% (570/1525)
unixを前提に考えると 親プロセスID:getppid(2) 自プロセスID:getpid(2) 子プロセスID:fork(2)の関数値 でわかると思います。 詳しくはmanでman 2 getpidなどとしてください。 (()内の数字がmanの第2パラメータ) 環境によって他にもやり方はあると思いますが上記の方法ならほとんどのunixで可能です。
補足
toysmithさんにはいつもいろいろ教えていただいてお世話になってます。 上記の件、確認したところ、IDが取れました。 ところで、もうひとつ追加質問なのですが、親とか、子のプロセスでなく、 まったく関係ないプロセスのプロセスIDをとることは可能ですか??
お礼
ありがとうございました! なんとか、子プロセスを終了することができました。 でも、まだまだわからない部分がいっぱいです。 もっと勉強しなくては。(^^ゞ とにもかくにも、a-kumaさん、toysmithさんありがとうございました。