按下CTRL-C时如何防止我的C程序终止?

Nik*_*ntz 2 linux signals process

AFAIK这与"捕获SIGINT"有关,但我正在寻找更多细节.像许多其他人一样,我通过编写自己的CLI来学习C,这个CLI可以启动环境变量所定位的其他程序.我的shell可以在前台和后台启动其他进程但是当按下CTRL-C来终止前台进程时,如何保持后台进程运行并且我的shell运行?我的部分代码是:

    int main() {
    /*... builtin commands and i/o ...*/
    isBackground = 0;
    for (b = 0; b<max; b++) {
        if ('&'==line[b])   {
            isBackground = 1;
        }
    }
    if (isBackground == 1)  {   /*If backgroundprocess*/
        printf("Background process\n");
        take_return=pipe(fd);  /*(two new file descriptors)*/
        pid_temp = fork();
    }
    else if (isBackground == 0) {   /*If foreground process*/
        printf("Foreground process\n");
        if (1 == isSignal)  {   /*If using signaldetection*/
            printf("Signal foreground\n");
            sigemptyset(&my_sig); /*empty and initialising a signal set*/
            sigaddset(&my_sig, SIGCHLD);    /*Adds signal to a signal set (my_sig)*/
            /*http://pubs.opengroup.org/onlinepubs/7908799/xsh/sigprocmask.html*/
            sigprocmask(SIG_BLOCK, &my_sig, NULL);
        }
        pid_temp = fork();
        foreground = pid_temp;  /*Set pid for foreground process*/
    }
    else if (0>pid_temp)    {
        /*Error*/
    }
    else    {
        /*Child process*/
        if (1 == isBackground)  {   /*Backgroundprocess*/
            dup2(fd[STDIN_FILENO], STDIN_FILENO);
            close(fd[0]);
            close(fd[1]);
        }
        /*http://www.lehman.cuny.edu/cgi-bin/man-cgi?execvp+2*/
        if (execvp(argv2[0],argv2) < 0) {
            printf("We are sorry to inform you that something went wrong %d \n", errno);
        }
    }
    if (0 == isBackground) {    /*Foregroundprocess*/
        waitpid(foreground, &status, 0);    /*Waiting*/
        printf("Foreground process id %d\n", foreground);
        /*Foregroundprocess terminated*/
        /*FIXME*/
        gettimeofday(&time_end, NULL);
        time = (time_end.tv_sec-time_start.tv_sec)*1000000 + time_end.tv_usec-time_start.tv_usec;
        printf("Execution time %ld ms\n", time);
        /*TODO Print out the execution time*/
        /*      int isSignal = 0;*/ /*FIXME*/
        if (1 == isSignal)  {   /*If using signaldetection*/
            int a = sigprocmask(SIG_UNBLOCK, &my_sig, NULL);
            /*http://man7.org/linux/man-pages/man2/sigprocmask.2.html*/
            if (0 == a) {
                /*Sigprocmask was successfull*/
            }
            else    {
                /*Sigprocmask was not successfull, return=-1*/
            }
            Janitor(SIGCHLD);
        }
        /*TODO Print how long time was the total execution time*/
    }
    else if (1==isBackground)   {
        close(fd[0]);
        close(fd[1]);
    }
}
/* pid= fork();
 if(pid==0) {
     execvp(progpath,argv);
     fprintf(stderr, "Child process could not do execvp\n");
 } else {
     wait(NULL);
     printf("Child exited\n");
 }*/
built_in_command = 0;   /*Reset*/
memset(line, 0, sizeof line); /*Reset*/
}
return (0);

}
Run Code Online (Sandbox Code Playgroud)

Bru*_*ger 5

您需要添加一个称为"信号处理程序"的函数.它有一个非常具体的类型.然后,您需要将代码更改为"安装信号处理程序".使用sigaction(2)系统调用最好这样做.所以,像这样:

#include <signal.h>
void sighandler(int, siginfo_t *, void *);

...

void
sighandler(int signo, siginfo_t *si, void *vp)
{
    write(2, "Received SIGINT\n", 16);
}
Run Code Online (Sandbox Code Playgroud)

main()你的程序执行任何耗费时间之前:

struct sigaction sa, osa;

sa.sa_sigaction = sighandler;
sa.sa_flags = SA_SIGINFO;
sigaction(SIGINT, &sa, &osa);
Run Code Online (Sandbox Code Playgroud)

您可能想要检查sigaction()错误的返回值.一旦你包含信号处理函数,并获得代码安​​装它在控件C发生之前执行,恭喜你,你有一个信号处理程序安装.

存在对代码的其他后果.某些系统调用(read(),close()名称为2)将返回错误(-1)并设置errno为EINTR.对套接字的读取特别容易发生这种情况.因此,为了避免丢失跟踪打开文件描述符和从套接字丢失数据等问题,您需要有代码来处理EINTR情况.

  • 不要忘记*仔细阅读[signal(7)](http://man7.org/linux/man-pages/man7/signal.7.html).通常,信号处理程序应该只设置一些`volatile sigatomic_t`标志,以便在其他地方进行测试. (2认同)