1

メインプログラムの pgid と pgroup を STDIN に設定する次の簡単なプログラムがあります。次に、現在のプロセスの pgid とシグナルの送信元プロセスの pgid を出力するシグナル ハンドラーがあります。これが私のコードです

pid_t pid;

void handler(int signum, siginfo_t* siginfo, void* context){
    printf("pgid is %d, shell_pgid is %d \n", getpgid(siginfo->si_pid), pid);
}


int main()
{
    struct sigaction sa;


    sa.sa_handler = handler;
    sigemptyset(&sa.sa_mask);
    sa.sa_flags = SA_RESTART; 

    sigaction(SIGINT, &sa, NULL);

    pid = getpid();
    setpgid(pid, pid);
    tcsetpgrp(STDIN_FILENO, pid);


      while(1){

      }
}

ただし、^Cを押すと、得られる出力は

^Cpgid is 335, shell_pgid is 3924 

プログラムはメインプログラムで実行されており、信号も同じソースから送信されているため、それらは同じであるはずではありませんか?

4

1 に答える 1

2

プロセス グループ ID の仕組みについて少し混乱していると思います。

まず、ソースを整理しました。

#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
#include <string.h>

pid_t pid;

void
handler (int signum, siginfo_t * siginfo, void *context)
{
  printf ("in signal handler pid is %d, getpgid(pid) is %d \n",
          pid, getpgid (pid));
  printf
    ("in signal handler siginfo->si_pid is %d, getpgid(siginfo->si_pid) is %d \n",
     siginfo->si_pid, getpgid (siginfo->si_pid));
  exit (0);
}


int
main (int argc, char **argv)
{
  struct sigaction sa;

  memset (&sa, 0, sizeof (sa));
  sa.sa_sigaction = handler;
  sigemptyset (&sa.sa_mask);
  sa.sa_flags = SA_RESTART | SA_SIGINFO;

  sigaction (SIGINT, &sa, NULL);

  pid = getpid ();
  printf ("before call pgid is %d pid=%d\n", getpgid (pid), pid);
  setpgid (pid, pid);
  printf ("after setpgid call pgid is %d pid=%d\n", getpgid (pid), pid);
  tcsetpgrp (STDIN_FILENO, pid);
  printf ("after tcsetprgrp call pgid is %d pid=%d\n", getpgid (pid), pid);

  while (1)
    {
    }
}

主な変更点は、ハンドラーが 3 つのパラメーターを受け取る場合、 notSA_SIGINFOでハンドラーを使用および指定する必要があることです。そうしないと、ハンドラーが無効な 2 番目と 3 番目の引数を取得する可能性があります。sa_sigactionsa_handler

次に、ハンドラーを修正してsi_pidpid.

また、追加のデバッグも行いました。

シェルから直接実行すると、次のようになります。

$ ./x
before call pgid is 15136 pid=15136
after setpgid call pgid is 15136 pid=15136
after tcsetprgrp call pgid is 15136 pid=15136
^Cin signal handler pid is 15136, getpgid(pid) is 15136
in signal handler siginfo->si_pid is 0, getpgid(siginfo->si_pid) is 15136

は を介し​​て送信された信号によってのみ埋められるsiginfo->si_pidため、 は 0 としてレポートされることに注意してください。これは 0 が渡されることを意味し、これは当然のことながら、前の行で返されたものと同じです。si_pidkillgetpgid()PGIDgetpgid(pid)

kill -SIGINTを押すのではなく、別のプロセスからで強制終了するとどうなりますか^C

$ ./x
before call pgid is 15165 pid=15165
after setpgid call pgid is 15165 pid=15165
after tcsetprgrp call pgid is 15165 pid=15165
in signal handler pid is 15165, getpgid(pid) is 15165
in signal handler siginfo->si_pid is 14858, getpgid(siginfo->si_pid) is 14858

ご覧のとおり、最後の行は、kill.

上記の両方の例で、プロセスが開始さPGIDれた時点で、 はすでに に等しくなっています。PID何故ですか?さて、コマンド ラインから 1 つのコマンドを起動したため、1 つのプロセス グループ (のみ) が存在するため、PGIDは常に になりますPID

では、最初のプロセスではないプロセス グループを起動するとどうなるでしょうか。これを試して:

$ echo | ./x
before call pgid is 15173 pid=15174
after setpgid call pgid is 15174 pid=15174
after tcsetprgrp call pgid is 15174 pid=15174
in signal handler pid is 15174, getpgid(pid) is 15174
in signal handler siginfo->si_pid is 14858, getpgid(siginfo->si_pid) is 14858

a は (が変更された後) のみであるプロセスグループに移動するkill -SIGINTため、これで強制終了する必要があったことに注意してください。したがって、オン エントリは(の PID ) ですが、 (要求したとおり) に変更されます。^CPGIDechoPGID15173echo15174

すべてが期待どおりに機能していると思います。

あなたが抱えている問題は、本質的にシグナルハンドラーにあると思います。最初に、あなたは記入されることを期待si_pidしているようです。次に、あなたprintfpgidand shell_pgid(2を印刷していると言っていますがPGID、実際にはPGIDkill を発行するプロセスの を印刷しています (または、ない場合、その結果はgetpgid(0)呼び出しPGIDプロセスの)、次にプロセスの PID - つまり、間違った方法と aPIDと aの両方PGID. また、ハンドラーの設定が間違っていると、とにかくジャンクの2番目のパラメーターが得られる可能性があると思われます。

于 2014-10-27T20:22:23.523 に答える