プロセスが予想されるプロセスグループの一部ではないのはなぜですか?

プロセスが予想されるプロセスグループの一部ではないのはなぜですか?

私はLinuxのプロセス、プロセスグループ(およびセッション)間の関係について学びます。

次のプログラムをコンパイルしました...

#include <iostream>
#include <ctime>
#include <unistd.h>

int main( int argc, char* argv[] )
{
  char buf[128];
  time_t now;
  struct tm* tm_now;
  while ( true )
  {
    time( &now );
    tm_now = localtime( &now );
    strftime( buf, sizeof(buf), "%a, %d %b %Y %T %z", tm_now );
    std::cout << buf << std::endl;
    sleep(5);
  }
  return 0;
}

...a.out次のようにバックグラウンドプロセスとして実行します。

a.out &

このウェブサイト次のように教えてください...

各プロセスは、プロセスグループIDによって識別される一意のプロセスグループのメンバーです。 (プロセスが作成されると、親プロセスグループのメンバーになります。)通常、プロセスグループのプロセスグループIDは、プロセスグループの最初のメンバー(プロセスグループリーダーと呼ばれる)のプロセスIDと同じです。 。

私が読んだところによると、最初の文は括弧内の内容と衝突します。ユニークプロセスグループまたはプロセスグループのメンバーその親の

調べてみましたがps

ps xao pid,ppid,pgid,sid,command | grep "PGID\|a.out"
  PID  PPID  PGID   SID COMMAND
24714 23890 24714 23890 ./a.out

これは私のa.outプロセスがpid24714であり、親pidで作成され、23890プログラムグループの一部であることを示しています24714。まず、このpgidがpidと一致する理由を理解できません。

次に、親プロセスを調べてみました。

ps xao pid,ppid,pgid,sid,command | grep "PGID\|23890"
  PID  PPID  PGID   SID COMMAND
23890 11892 23890 23890 bash
24714 23890 24714 23890 ./a.out

私の親プロセスa.outは私にとって意味がありますbash。最初は「と思いました。bashのpidはpgidと一致します。これはプロセスグループリーダーだからです。おそらくbashが実行される「最初のタスク」であり、私はbashでプロセスを実行するので、これは意味があるかもしれません。a.outしかし、pgidも自分のpidと一致するので、この推論は意味がありません。

a.outなぜ'のpgidが'のpgidと等しくないのですかbash?この文章の私の理解に基づいて、これが私が期待したものです。

誰かがpidとpgidの関係を明確にすることはできますか?

答え1

衝突はありません。デフォルトでは、プロセスは親である唯一のプロセスグループに属します。

$ cat pg.c
#include <stdio.h>
#include <unistd.h>
int main(void)
{
    fork();
    printf("pid=%d pgid=%d\n", getpid(), getpgrp());
}
$ make pg
cc     pg.c   -o pg
$ ./pg 
pid=12495 pgid=12495
pid=12496 pgid=12495
$ 

forkプロセスを親プロセス(12495)と子プロセス()に分割し、子プロセスは12496親プロセス()12495の一意のプロセスグループに属します。bash追加のシステムコールを実行するため、これとは異なります。

$ echo $$
12366
$

その後、別の端末で実行します。

$ strace -f -o blah -p 12366

その後、最初の端末に戻ります。

$ ./pg
pid=12676 pgid=12676
pid=12677 pgid=12676
$

次にシステムコールを確認しますcontrol+cstrace

$ egrep 'exec|pgid' blah
12366 setpgid(12676, 12676)             = 0
12676 setpgid(12676, 12676 <unfinished ...>
12676 <... setpgid resumed> )           = 0
12676 execve("./pg", ["./pg"], [/* 23 vars */]) = 0
12676 write(1, "pid=12676 pgid=12676\n", 21 <unfinished ...>
12677 write(1, "pid=12677 pgid=12676\n", 21 <unfinished ...>

bashこのsetpgid呼び出しを使用してプロセスグループを設定することによって、pgプロセスをシェルに依存しないプロセスグループに配置します。 (setsid(2)システムコールを探している場合は、プロセスグループを調整する別の方法になります。)

答え2

Bash は、ジョブ制御処理の一部としてプログラムを独自のプロセスグループに入れます。たとえば、bashのマンページでは:

タスク制御ユーザーインターフェースの実装を容易にするために、オペレーティングシステムは現在の端末プロセスグループIDの概念を維持しています。このプロセスグループのメンバー(現在の端末のプロセスグループIDと同じプロセスグループIDを持つプロセス)は、SIGINTなどのキーボード生成信号を受け取ります。これらのプロセスは前景にあると言われています。バックグラウンドプロセスは、プロセスグループIDが端末プロセスグループIDと異なるプロセスである。これらのプロセスはキーボードから生成された信号の影響を受けません。フォアグラウンドプロセスのみが端末を読み書きできます(ユーザーがstty tostopを使用して指定した場合)。カーネルの端末ドライバは、端末から読み込みを試みる(そしてstty tostopが適用されたときに書き込みを試みます)、バックグラウンドプロセスにSIGTTIN(SIGTTOU)信号を送信し、プロセスがキャッチされない限り停止します。

またset -m

モニターモード。ジョブ制御が有効になりました。このオプションは、それをサポートするシステムの対話型シェルに対してデフォルトで有効になっています(上記のタスク制御を参照)。すべてのプロセスは別々のプロセスグループで実行されます。バックグラウンドジョブが完了すると、シェルは終了ステータスを含む行を印刷します。

したがって、期待する動作が必要な場合は、次のことができます。

  1. forkBashなしでプロセスを生成するためにコードで使用されます。
  2. set +mBashで監視モードをオフにするために使用されます。fgしかし、これはそのようなものを破るでしょう。

関連情報