2017-10-01 111 views
2

我目前正在尝试通过使用它们来控制用fork()方法创建的子进程来使用C中的信号。从本质上讲,我有一个子进程从linux终端运行“是”命令(该命令只是打印“y”和一个换行符,直到它终止)。我希望能够用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”。关于为什么儿童进程不恢复的任何想法?

回答

3

事实证明,system在其中有一个隐含的分叉调用,所以存储在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. 

所以,如果我们更换system("yes")电话与execl("/bin/sh", "sh", "-c", "yes", NULL),那么我们避免根据需要这个额外的叉子和程序功能。


唯一的另一个问题是,通过我的评论,我发现on this post,信号处理程序中使用printf是不确定的行为。这里不是一个值得担心的问题,但需要注意以后的代码!

+1

'规范'问答是[如何避免在信号处理程序中使用'printf()'](http://stackoverflow.com/questions/16891019/how-to-avoid-using-printf-in-一个信号处理程序/) –