使用信号处理程序 Pause/Resume 子进程
Using Signal Handlers to Pause/Resume a Child Process
我目前正在尝试使用 C 中的信号来控制使用 fork() 方法创建的子进程。本质上,我有一个子进程 运行 从 linux 终端执行 "yes" 命令(此命令只打印 "y" 和一个换行符,直到它终止)。我希望能够使用 CTRL-Z pause/resume 这个过程。这就是我现在得到的:
#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 pressed. Pausing child." 打印到控制台,我可以通过按 CTRL- "Ctrl-Z pressed. Resuming child." 打印到控制台又是Z。但是,它实际上并没有一遍又一遍地恢复打印 "y" 。关于为什么子进程没有恢复的任何想法?
事实证明,system
中有一个隐式的 fork 调用,因此存储在 CHILD_PROCESS
中的 PID 实际上不是子进程,而是一个中间进程。
来自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
是未定义的行为。这不是一个需要担心的问题,但在以后的代码中要记住一些事情!
我目前正在尝试使用 C 中的信号来控制使用 fork() 方法创建的子进程。本质上,我有一个子进程 运行 从 linux 终端执行 "yes" 命令(此命令只打印 "y" 和一个换行符,直到它终止)。我希望能够使用 CTRL-Z pause/resume 这个过程。这就是我现在得到的:
#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 pressed. Pausing child." 打印到控制台,我可以通过按 CTRL- "Ctrl-Z pressed. Resuming child." 打印到控制台又是Z。但是,它实际上并没有一遍又一遍地恢复打印 "y" 。关于为什么子进程没有恢复的任何想法?
事实证明,system
中有一个隐式的 fork 调用,因此存储在 CHILD_PROCESS
中的 PID 实际上不是子进程,而是一个中间进程。
来自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
是未定义的行为。这不是一个需要担心的问题,但在以后的代码中要记住一些事情!