进程被杀死多次没有收到信号 SIGUSR1

如何解决进程被杀死多次没有收到信号 SIGUSR1

我有 2 个 .c 脚本。一个是father.c:

#include <stdio.h>
#include <unistd.h>
#include <signal.h>
#include <stdlib.h>

pid_t childPid;
void createChild(){
    fprintf(stderr,"creating a new child\n");
    childPid=fork();
    if(childPid==0){
        execlp("./child","child",NULL);
        perror("err");
    }
    fprintf(stderr,"created child pid is %d\n",childPid);
}
void signalHandler(int signal){
    if(signal==SIGUSR1){
        kill(childPid,SIGINT);
        createChild();
    }
}

int main(int argc,char ** argv){
    signal(SIGUSR1,signalHandler);
    signal(SIGCHLD,SIG_IGN);    
    createChild();/*create first child*/    
    while(1){
        sleep(2);
        int ret=kill(childPid,SIGUSR1);
        if(ret==-1){
            perror("exit err ");
        }
    }
}


另一个是child.c:

#include <stdio.h>
#include <unistd.h>
#include <signal.h>

void signalHandler(int signal){
    if(signal==SIGUSR1){
        fprintf(stderr,"child process received signal\n");
        kill(getppid(),SIGUSR1);
    }
}

int main(int argc,char ** argv){
    fprintf(stderr,"i'm the new child with pid %d\n",getpid());
    if(signal(SIGUSR1,signalHandler)==SIG_ERR){
        fprintf(stderr,"error");
    }
    while(1){}
}

当父亲启动时,它应该每2秒杀死一个孩子,分叉自己并开始一个新的孩子。 通过向他发送 SIGUSR1 信号来杀死孩子,该信号被处理并转发给父亲(使用另一个 SIGUSR1 信号),父亲用 SIGINT 杀死孩子。 我面临的问题是第二次创建孩子时,它不再接收 SIGUSR1 信号。 有人可以帮忙吗?

编辑:感谢@CraigEstey(见下面他的回答),他发现从子进程向父进程发送不同的信号确实可以完成工作。 按照这个建议,我上面发布的代码应该像这样更改(为了使其工作):在father.c中将if(signal==SIGUSR1)替换为if(signal==SIGUSR2),将signal(SIGUSR1,signalHandler);替换为{{1} }. 在 child.c 中,将 signal(SIGUSR2,signalHandler); 替换为 kill(getppid(),SIGUSR1);。 如果这不是您想要的,我建议您阅读@CraigEstey 的回答,他详细解释了所有内容,并为两个进程提供了使用相同信号编号的工作代码。

解决方法

一些事情......

当子进程向父进程发送信号时,父进程在 sleep 调用中。这会提前终止(例如 EINTR)。

因此,在第二轮中,父母将[可能]在孩子准备接收信号之前杀死孩子。

为了添加调试、waitpid 等,我进行了一些重大修改。

主要问题是[要么]第二个孩子没有从父母那里得到SIGUSR1。或者,孩子没有将信号发送给父母或父母被阻止。从下面的第二个日志文件来看,第二个孩子似乎从未从父母那里得到 SIGUSR1

我添加了额外的 signal 调用来重新装备处理程序 [可能不需要]。我添加了 waitpid 次调用

在我让父母和孩子使用不同信号之前,我无法让事情发挥作用。也就是说,parent 将 SIGUSR1 发送给 child,child 将 SIGUSR2 发送给 parent。

这可能不是您想要的,而且我 [还] 不明白为什么信号数量差异很重要。

查看 /proc/pid/status 中的信号掩码可能有助于辨别可能发生的情况。

编辑:使代码完全运行。有关详细信息,请参阅下面的更新部分。


这是“坏”日志。父母会在孩子进行设置之前发送第二个信号:

SIGUSR1 is 10
SIGUSR2 is 12
SIGTERM is 15
SIGINT is 2
SIGDN is 10
SIGUP is 10
SIGFIX is 0
KILLERR is 0
QSLEEP is 0

creating a new child
created child pid is 738524
i'm the new child with pid 738524
while forever
killing child with SIGDN 738524
child got signal 10
child killing parent 738523
parent received signal 10
killing child with SIGINT 738524
waitpid on 738524

creating a new child
created child pid is 738525
killing child with SIGDN 738525
i'm the new child with pid 738525
while forever
killing child with SIGDN 738525
killing child with SIGDN 738525
killing child with SIGDN 738525
killing child with SIGDN 738525

请注意,如果我们将 KILLERR 选项添加到构建中,则 kill 从父到子的 SIGUSR1 调用将产生 ESRCH 错误(无此过程) .


如果我们有父级的 sleep 调用循环并等待 2 秒(例如它计算睡眠的剩余时间),我们会得到一个不同的序列。父母只会在孩子有时间设置后发送 SIGUSR1

SIGUSR1 is 10
SIGUSR2 is 12
SIGTERM is 15
SIGINT is 2
SIGDN is 10
SIGUP is 10
SIGFIX is 0
KILLERR is 0
QSLEEP is 1

creating a new child
created child pid is 739105
i'm the new child with pid 739105
while forever
killing child with SIGDN 739105
child got signal 10
child killing parent 739104
parent received signal 10
killing child with SIGINT 739105
waitpid on 739105

creating a new child
created child pid is 739106
i'm the new child with pid 739106
while forever
killing child with SIGDN 739106
killing child with SIGDN 739106
killing child with SIGDN 739106
killing child with SIGDN 739106

这是工作日志:

SIGUSR1 is 10
SIGUSR2 is 12
SIGTERM is 15
SIGINT is 2
SIGDN is 10
SIGUP is 12
SIGFIX is 1
KILLERR is 0
QSLEEP is 1

creating a new child
created child pid is 740214
i'm the new child with pid 740214
while forever
killing child with SIGDN 740214
child got signal 10
child killing parent 740213
parent received signal 12
killing child with SIGINT 740214
waitpid on 740214

creating a new child
created child pid is 740215
i'm the new child with pid 740215
while forever
killing child with SIGDN 740215
child got signal 10
child killing parent 740213
parent received signal 12
killing child with SIGINT 740215
waitpid on 740215

creating a new child
created child pid is 740216
i'm the new child with pid 740216
while forever
killing child with SIGDN 740216
child got signal 10
child killing parent 740213
parent received signal 12
killing child with SIGINT 740216
waitpid on 740216

creating a new child
created child pid is 740218
i'm the new child with pid 740218
while forever
killing child with SIGDN 740218
child got signal 10
child killing parent 740213
parent received signal 12
killing child with SIGINT 740218
waitpid on 740218

creating a new child
created child pid is 740219
i'm the new child with pid 740219
while forever

更新:

最初,我是按照您的评论说您使用了 sigaction,所以我没有尝试。

但是,我添加了 sigaction 作为选项(以及用于解除信号阻塞的 sigprocmask 调用——这可能更重要)。

即使信号编号相同,这也有效

我已经更新了下面的代码,但我保留了上一篇博文中的 [above] 日志文件。


这是源代码。我添加了 common.cMakefile

==> child.c <==
#include <stdio.h>
#include <unistd.h>
#include <signal.h>
#include <string.h>

#include "common.c"

pid_t ppid;

void
signalHandler(int signo)
{
    xsignal2(SIGDN,signalHandler);

    msg2("child got signal",signo);

    if (signo == SIGDN) {
        msg2("child killing parent",ppid);
        qkill(ppid,SIGUP);
    }
}

int
main(int argc,char **argv)
{

    ppid = getppid();

    xsignal(SIGDN,signalHandler);
    msg2("i'm the new child with pid",getpid());

    msg("while forever\n");
    while (1) {
    }
}

==> common.c <==
#include <time.h>
#include <stdlib.h>
#include <errno.h>

typedef long long tsc_t;
#define NSEC        1000000000

#ifndef SIGFIX
#define SIGFIX      0
#endif

#ifndef SIGACT
#define SIGACT      0
#endif

#ifndef KILLERR
#define KILLERR     0
#endif

#if SIGFIX
#define SIGDN       SIGUSR1
#define SIGUP       SIGUSR2
#else
#define SIGDN       SIGUSR1
#define SIGUP       SIGUSR1
#endif

#ifndef QSLEEP
#define QSLEEP      0
#endif

void
xsignal(int signo,void (*fnc)(int))
{

#if SIGACT
    struct sigaction act;
    sigset_t set;

    memset(&act,sizeof(act));
    act.sa_handler = (void *) fnc;
    sigaction(signo,&act,NULL);

    sigemptyset(&set);
    sigaddset(&set,signo);
    sigprocmask(SIG_UNBLOCK,&set,NULL);
#else
    signal(signo,fnc);
#endif
}

void
xsignal2(int signo,void (*fnc)(int))
{

#if ! SIGACT
    xsignal(signo,fnc);
#endif
}

tsc_t
tscget(void)
{
    struct timespec ts;
    tsc_t tsc;

    clock_gettime(CLOCK_MONOTONIC,&ts);

    tsc = ts.tv_sec;
    tsc *= NSEC;
    tsc += ts.tv_nsec;

    return tsc;
}

void
msg(const char *str)
{
    size_t len = strlen(str);
    write(2,str,len);
}

void
num(tsc_t val)
{
    char *rhs;
    char *lhs;
    char buf[100];

    lhs = buf;
    rhs = buf;

    while (val > 0) {
        *rhs++ = (val % 10) + '0';
        val /= 10;
    }

    if (rhs <= buf)
        *rhs++ = '0';

    *rhs-- = 0;

    for (;  lhs < rhs;  ++lhs,--rhs) {
        int tmp = *lhs;
        *lhs = *rhs;
        *rhs = tmp;
    }

    msg(buf);
}

void
msg2(const char *str,tsc_t val)
{

    msg(str);
    msg(" ");
    num(val);
    msg("\n");
}

void
qkill(pid_t pid,int signo)
{
    int err;

    err = kill(pid,signo);
    if (err < 0) {
        err = errno;
#if KILLERR
        msg2("qkill: failed -- err is",err);
        exit(1);
#endif
    }
}

void
qsleep(int sec)
{
    tsc_t nsec;
    tsc_t beg;
    tsc_t now;
    struct timespec ts;

    nsec = sec;
    nsec *= NSEC;

    while (nsec > 0) {
        beg = tscget();

        ts.tv_nsec = nsec % NSEC;
        ts.tv_sec = nsec / NSEC;
        nanosleep(&ts,NULL);

        now = tscget();
        now -= beg;

        nsec -= now;
    }
}

==> parent.c <==
#include <stdio.h>
#include <unistd.h>
#include <signal.h>
#include <stdlib.h>
#include <string.h>
#include <sys/wait.h>
#include <syscall.h>

#include "common.c"

pid_t childPid;

void
createChild()
{

    msg("\n");
    msg("creating a new child\n");

#if 0
    childPid = fork();
#else
    childPid = syscall(SYS_fork);
#endif
    if (childPid == 0) {
        execlp("./child","child",NULL);
        perror("err");
        exit(1);
    }

    msg("created child pid is ");
    num(childPid);
    msg("\n");
}

void
signalHandler(int signo)
{

    msg2("parent received signal",signo);

    if (signo == SIGUP) {
        xsignal2(SIGUP,signalHandler);

        msg2("killing child with SIGINT",childPid);
#if 0
        qkill(childPid,SIGTERM);
#else
        qkill(childPid,SIGKILL);
#endif

        msg2("waitpid on",childPid);
        waitpid(childPid,NULL,0);

        createChild();
    }
}

int
main(int argc,char **argv)
{

    msg2("SIGUSR1 is",SIGUSR1);
    msg2("SIGUSR2 is",SIGUSR2);
    msg2("SIGTERM is",SIGTERM);
    msg2("SIGINT is",SIGINT);
    msg2("SIGDN is",SIGDN);
    msg2("SIGUP is",SIGUP);

    msg2("SIGFIX is",SIGFIX);
    msg2("SIGACT is",SIGACT);
    msg2("KILLERR is",KILLERR);
    msg2("QSLEEP is",QSLEEP);

    xsignal(SIGUP,signalHandler);
    signal(SIGCHLD,SIG_IGN);

    createChild();                      /* create first child */

    while (1) {
#if QSLEEP
        qsleep(2);
#else
        sleep(2);
#endif

        msg2("killing child with SIGDN",childPid);
        int ret = kill(childPid,SIGDN);

        if (ret == -1) {
            perror("exit err ");
        }

        //msg2("waitpid on",childPid);
        //waitpid(childPid,0);
    }
}

==> Makefile <==
PGM += child
PGM += parent

all: $(PGM)

$(PGM):
    cc -o $@ $@.c $(CFLAGS) -Wall

clean:
    rm -f $(PGM)

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


使用本地python环境可以成功执行 import pandas as pd import matplotlib.pyplot as plt # 设置字体 plt.rcParams[&#39;font.sans-serif&#39;] = [&#39;SimHei&#39;] # 能正确显示负号 p
错误1:Request method ‘DELETE‘ not supported 错误还原:controller层有一个接口,访问该接口时报错:Request method ‘DELETE‘ not supported 错误原因:没有接收到前端传入的参数,修改为如下 参考 错误2:cannot r
错误1:启动docker镜像时报错:Error response from daemon: driver failed programming external connectivity on endpoint quirky_allen 解决方法:重启docker -&gt; systemctl r
错误1:private field ‘xxx‘ is never assigned 按Altʾnter快捷键,选择第2项 参考:https://blog.csdn.net/shi_hong_fei_hei/article/details/88814070 错误2:启动时报错,不能找到主启动类 #
报错如下,通过源不能下载,最后警告pip需升级版本 Requirement already satisfied: pip in c:\users\ychen\appdata\local\programs\python\python310\lib\site-packages (22.0.4) Coll
错误1:maven打包报错 错误还原:使用maven打包项目时报错如下 [ERROR] Failed to execute goal org.apache.maven.plugins:maven-resources-plugin:3.2.0:resources (default-resources)
错误1:服务调用时报错 服务消费者模块assess通过openFeign调用服务提供者模块hires 如下为服务提供者模块hires的控制层接口 @RestController @RequestMapping(&quot;/hires&quot;) public class FeignControl
错误1:运行项目后报如下错误 解决方案 报错2:Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.8.1:compile (default-compile) on project sb 解决方案:在pom.
参考 错误原因 过滤器或拦截器在生效时,redisTemplate还没有注入 解决方案:在注入容器时就生效 @Component //项目运行时就注入Spring容器 public class RedisBean { @Resource private RedisTemplate&lt;String
使用vite构建项目报错 C:\Users\ychen\work&gt;npm init @vitejs/app @vitejs/create-app is deprecated, use npm init vite instead C:\Users\ychen\AppData\Local\npm-
参考1 参考2 解决方案 # 点击安装源 协议选择 http:// 路径填写 mirrors.aliyun.com/centos/8.3.2011/BaseOS/x86_64/os URL类型 软件库URL 其他路径 # 版本 7 mirrors.aliyun.com/centos/7/os/x86
报错1 [root@slave1 data_mocker]# kafka-console-consumer.sh --bootstrap-server slave1:9092 --topic topic_db [2023-12-19 18:31:12,770] WARN [Consumer clie
错误1 # 重写数据 hive (edu)&gt; insert overwrite table dwd_trade_cart_add_inc &gt; select data.id, &gt; data.user_id, &gt; data.course_id, &gt; date_format(
错误1 hive (edu)&gt; insert into huanhuan values(1,&#39;haoge&#39;); Query ID = root_20240110071417_fe1517ad-3607-41f4-bdcf-d00b98ac443e Total jobs = 1
报错1:执行到如下就不执行了,没有显示Successfully registered new MBean. [root@slave1 bin]# /usr/local/software/flume-1.9.0/bin/flume-ng agent -n a1 -c /usr/local/softwa
虚拟及没有启动任何服务器查看jps会显示jps,如果没有显示任何东西 [root@slave2 ~]# jps 9647 Jps 解决方案 # 进入/tmp查看 [root@slave1 dfs]# cd /tmp [root@slave1 tmp]# ll 总用量 48 drwxr-xr-x. 2
报错1 hive&gt; show databases; OK Failed with exception java.io.IOException:java.lang.RuntimeException: Error in configuring object Time taken: 0.474 se
报错1 [root@localhost ~]# vim -bash: vim: 未找到命令 安装vim yum -y install vim* # 查看是否安装成功 [root@hadoop01 hadoop]# rpm -qa |grep vim vim-X11-7.4.629-8.el7_9.x
修改hadoop配置 vi /usr/local/software/hadoop-2.9.2/etc/hadoop/yarn-site.xml # 添加如下 &lt;configuration&gt; &lt;property&gt; &lt;name&gt;yarn.nodemanager.res