我当前正在尝试通过使用fork()方法创建的子过程来尝试C中的信号。从本质上讲,我有一个子进程从Linux终端运行"是"命令(此命令只是打印" y"和一个newline,直到终止)。我希望能够使用CTRL-Z暂停/恢复此过程。这就是我现在得到的:
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
pid_t CHILD_PROCESS;
pid_t PARENT_PROCESS;
int isPaused;
void pause_handler(int signo){
if(!isPaused){
printf("Ctrl-Z pressed. Pausing child.n");
isPaused = 1;
kill(CHILD_PROCESS,SIGSTOP);
}
else if(isPaused){
printf("nCtrl-Z pressed. Resuming child.n");
kill(CHILD_PROCESS,SIGCONT);
isPaused = 0;
}
}
int main(int argc, char** argv){
pid_t pid;
PARENT_PROCESS = getpid();
pid = fork();
if(pid == 0){
system("yes");
}
isPaused = 0;
if(pid > 0){
signal(SIGTSTP, SIG_IGN);
signal(SIGSTOP, SIG_IGN);
CHILD_PROCESS = pid;
while(1){
if(signal(SIGTSTP,pause_handler) == SIG_ERR){
printf("Signal Failure");
}
}
}
}
当我运行此操作时,我可以"按下Ctrl-Z。暂停孩子"。通过按CTRL-Z打印到控制台,我可以得到" ctrl-Z"。恢复孩子。再次按CTRL-Z打印到控制台。但是,它实际上并未一遍又一遍地恢复" Y"。关于为什么没有恢复孩子的过程有什么想法?
事实证明, system
中有一个隐式的叉呼叫,因此存储在CHILD_PROCESS
中的PID最终并不是儿童过程,而是一个中间的PID。P>
来自man 3 system
:
The system() library function uses fork(2) to create a child process
that executes the shell command specified in command using execl(3) as
follows:
execl("/bin/sh", "sh", "-c", command, (char *) 0);
system() returns after the command has been completed.
因此,如果我们用execl("/bin/sh", "sh", "-c", "yes", NULL)
替换system("yes")
调用,那么我们避免使用此额外的叉子,并且该程序可根据需要进行功能。
唯一的问题是,通过我在这篇文章中发现的评论,在信号处理程序中使用printf
是未定义的行为。在这里不是要担心的问题,而是要记住的未来代码的问题!