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);
}
答案 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情况。