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

时间:2015-05-19 19:44:01

标签: linux process signals

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);

}

1 个答案:

答案 0 :(得分:5)

您需要添加一个名为&#34;信号处理程序&#34;的函数。它有一个非常具体的类型。然后,您需要将代码更改为&#34;安装信号处理程序&#34;。使用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);
}

main()内,在你的程序耗费任何时间之前:

struct sigaction sa, osa;

sa.sa_sigaction = sighandler;
sa.sa_flags = SA_SIGINFO;
sigaction(SIGINT, &sa, &osa);

您可能需要检查sigaction()的返回值是否有错误。一旦你包含信号处理函数,并获得代码来安装它在control-C发生之前执行,恭喜你,你已经安装了信号处理程序。

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