gpt4 book ai didi

c - 信号处理程序中的 pgid 与真实 pgid 不同

转载 作者:太空宇宙 更新时间:2023-11-04 02:46:43 26 4
gpt4 key购买 nike

我有以下简单程序,它为 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)
{
}
}

主要的变化是如果你的handler需要三个参数,你需要使用SA_SIGINFO并在 sa_sigaction 中指定处理程序不是sa_handler .否则,您的处理程序可能会获得无效的第二个和第三个参数。

接下来我修复了你的处理程序,所以它打印出 si_pid以及pid .

我还进行了一些额外的调试。

这是我直接从 shell 运行时发生的情况:

$ ./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,因为 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说你正在打印 pgidshell_pgid (两个 PGID s,而实际上你正在打印发出 kill 的进程的 PGID (或者如果没有 getpgid(0) 的结果,它是调用进程的 PGID),那么进程的 PID -即错误的方式和 PIDPGID 。而且我怀疑设置错误的处理程序可能会给你一个垃圾第二参数。

关于c - 信号处理程序中的 pgid 与真实 pgid 不同,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26593178/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com