C 信号处理程序中的pgid与实际pgid不同

C 信号处理程序中的pgid与实际pgid不同,c,signals,process-group,C,Signals,Process Group,我有一个简单的程序,为STDIN设置主程序的pgid和pgroup。然后,我有一个信号处理程序,它打印当前进程的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()

我有一个简单的程序,为STDIN设置主程序的pgid和pgroup。然后,我有一个信号处理程序,它打印当前进程的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 

难道它们不应该是相同的,因为程序在主程序中运行,信号也从相同的源发送吗

我认为您可能对进程组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)
    {
    }
}
请注意,
siginfo->si_pid
报告为0,因为
si_pid
仅由通过
kill
发送的信号填充。这意味着0被传递到
getpgid()
,它返回调用进程的
PGID
,这与前一行返回的
getpgid(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
的进程的PID

在上述两个示例中,当流程启动时,
PGID
已经等于
PID
。为什么呢?我们从命令行启动了一个命令,因此只有一个进程组(仅),因此
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
请注意,我必须使用
kill-SIGINT
终止这个进程,因为
^C
会转到进程组,而进程组(在
PGID
更改后)只
echo
。因此,条目上的
PGID
15173
echo
的PID),但会更改为
15174
(根据您的请求)

我想一切都按预期进行了


我认为你的问题本质上在于你的信号处理器。首先,您似乎希望填写
si_pid
。其次,您的
printf
表示您正在打印
pgid
shell\u pgid
(两个
pgid
s,而实际上您正在打印发出kill的进程的
pgid
(如果没有),则打印
getpgid(0)
的结果,这是调用进程的
pgid
),然后进程的PID-即错误的循环方式和a
PID
和a
PGID
。而且我怀疑设置错误的处理程序可能会给您提供第二个参数。

setpgid()
call successing?@abligh我运行了你的程序并在main中终止,但我的输出是221:src frabi$。/getpgid在调用前pgid是4758,在setpgid调用后pgid是4758,在tcsetprgrp调用后pgid是4758,在信号处理程序siginfo->si_pid是335,getpgid是4758(siginfo->si_pid)是335对,所以你直接从shell启动,所以在你开始之前,你的
PGID
和你的
PID
已经相等了。看起来当你杀死它时,你得到了一个
si_PID
集。这可能取决于你的
^C
处理是如何完成的。我是通过
ssh
登录的。不管怎样,我猜是335是你的壳的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