【问题标题】:C child process doesn't receive SIGINT signalC子进程没有收到SIGINT信号
【发布时间】:2019-01-29 14:56:53
【问题描述】:

我在处理信号方面遇到了一些问题。我正在创建一个简单的 Web 服务器,但我不明白为什么我的初始进程成功捕获并处理了 SIGINT 信号,但子进程处理它 fork()s 似乎没有这样做。这是我的代码:

#include <sys/types.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <signal.h>
#include <errno.h>
#include <time.h>
#include <sys/stat.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <unistd.h>
#include <fcntl.h>
#include <stdio.h>
#include "thpool.h"
#include <pthread.h>
#include <string.h>
#include <arpa/inet.h>
#include <sys/sendfile.h>

int asc;
threadpool thpool;

void sighand(int sig) { //function handler
    if (sig == SIGINT) {
        printf("ctr-c recived\n");
        go = 0;
        thpool_destroy(thpool);
        shutdown(asc, 2);
        close(asc);
        int a = 1;
        setsockopt(asc, SOL_SOCKET, SO_REUSEADDR, &a, sizeof(int));
        exit(2);
}

void fun(void *client_socket) { 
    int sock = *(int*)client_socket;
    char buffer[1024]; 
    int n = read(sock, buffer, BUFFERSIZE);
    printf("%s\n", buffer);
}

int main() {
    int pid;

    if (signal(SIGINT, sighand) == SIG_ERR) //signal function
        perror("signal failed\n);
    pid = fork();
    if (pid == 0) { //new process
        int port = 8666, client_socket;
        struct sockaddr_in server, client;
        pthread_mutex_t M;
        pthread_mutex_init(&M,NULL);
        int parent = getppid();
        value = kill(parent, SIGTERM);  //kill the parent
        if (value == 0)
            printf("dead parent\n");
        else
            perror("errore");
        thpool = thpool_init(2); 

        //creazione socket
        asc = socket(AF_INET, SOCK_STREAM, 0); //new socket
        printf("\nsocket aperto\n");
        bzero((char *)&server, sizeof(server));

        //inizializzazione
        memset(&server, 0, sizeof(server));
        server.sin_family = AF_INET;
        server.sin_addr.s_addr = INADDR_ANY;
        server.sin_port = htons(port);
        bind(asc, (struct sockaddr *)&server, sizeof(struct sockaddr_in)
        printf("bind effettuata\n");
        listen(asc, 40) 
        printf("listen effettuata\n");
        printf("in attesa di connessione....\n");
        client_leng = sizeof(client);
        while (go) {
            if ((client_socket = accept(asc, (struct sockaddr *)&client, &client_leng)) < 0) {
                perror("accept fallita");
                exit(0);
            } else {
                pthread_mutex_lock(&M);
                printf("accept effettuata\n");
                thpool_add_work(thpool, (void *)fun, (void *)&client_socket);
                puts("handler assigned\n");
                pthread_mutex_unlock(&M);
            }
        }
    }

【问题讨论】:

  • 处理信号的代码在哪里?提供minimal reproducible example 意味着我们更有可能回答您的问题
  • ...如果有的话,孩子实际上做了什么?你是如何向它传递信号的?你确定你成功传递了信号吗?这类问题是我们要求 MCVE 的原因。
  • @Davide,当你说信号处理程序没有被调用时,你指的是哪个进程,是子进程还是父进程?
  • 通过fork() 创建的子进程确实继承了其父进程的信号处置。如果您的实验对您提出其他建议,则说明该实验有缺陷,或者您对其结果的解释有缺陷,但我们无法告诉您该缺陷的性质没有更多细节。
  • 我看到的代码不包括据称向子进程发送信号的父代码。您如何启动此代码?你在shell中使用后台操作符&amp;吗?这有后果……同样,我们需要一个 MCVE(在您的情况下,强调 complete,意思是“足够完整可以运行”,并说明代码如何运行以及向其提供哪些输入(如果有的话)等等。

标签: c signals


【解决方案1】:

TL;DR:您发出的信号与您认为的不同。

您在 cmets 中提到您正尝试通过在键盘上键入 CTRL-C 将 SIGINT 传递给您的进程。当您想杀死终端的前台进程组然后拥有键盘时,这很好。假设你从一个 shell 窗口启动你的程序并且它没有将自己置于后台,那么初始进程确实会在前台进程组中,如果你从来没有 fork() 那么你所做的任何事情都不会改变它,直到进程终止。因此,在该终端中键入 CTRL-C 将向该进程传递一个SIGINT

但是,当初始进程终止时,启动它的 shell 会将自己重新置于前台。您可以通过输入命令来检查它。此外,在初始进程成功fork()s 一个子进程的情况下,当shell 将自己置于前台时,该子进程及其进程组将进入后台。 此时,您键入的任何 CTRL-C 都会进入 shell(忽略它),而不是 Web 服务器进程的子进程。

例如,您可以通过kill 命令将SIGINT 发送到在后台运行或没有控制终端的进程

kill -INT 12345

如果您在forking 案例中使用该方法将SIGINT 传递给子进程,您将看到该进程的注册信号处理程序完全按照应有的方式捕获和处理信号。

【讨论】: