2017-10-01 110 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-一個信號處理程序/) –