2017-10-11 62 views
1

基本上我有两个代码。 其中之一必须在shell中打印“TIME!”每次它收到一个SIGUSR1信号。 我们称之为exercici.cC,fork和exec进程,并发送信号

#include <stdlib.h> 
#include <unistd.h> 
#include <stdio.h> 
#include <signal.h> 

char buffer[1000]; 

void captura_signal(int signum){ 

    if(signum == SIGUSR1){ 
     sprintf(buffer,"TIME! %d\n",getpid()); 
     write(1,buffer,strlen(buffer)); 
    } 
} 


int main(int argc, char *argv[]){ 
    signal(SIGUSR1, captura_signal); 
    while(1){ 
     pause(); 
    } 

} 

另一种,必须创建三个子进程(只有一个父和三个孩子的)和execlp exercici.c上的每个孩子。然后,父母每秒都必须向一个孩子发送一个SIGUSR1,每秒递增一个。我称之为exercici2.c

#include <stdlib.h> 
#include <unistd.h> 
#include <stdio.h> 
#include <stdbool.h> 
#include <signal.h> 


bool ready = 1; 

void sigAlarm(int sig){ 
    if (sig == SIGALRM){ 
     ready = 1; 
    } 
} 


int main(int argc, char *argv[]){ 
    int pid[3]; 
    signal(SIGALRM,sigAlarm); 
    for(int i = 0; i<3;i++){ 
     if((pid[i]=fork()) == 0){ 
      execlp("./exercici","exercici",(char*)NULL); 
     } 
    } 
    int j =0; 
    while(1){ 
     if(ready){ 
      ready = 0; 
      kill(pid[j],SIGUSR1); 
      j = ((j+1)%3); 
      alarm(1); 
     } 
    } 
} 

的问题是,当我执行exercici2.c它将只创建2个进程,我只接收时间!其中2个。它跳过一个pid [0]。

shell image

+0

你可以在'fork'(测试fork()== -1')中测试错误,并使用'perror'打印出任何错误吗? (小贴士:考虑一个switch语句,其中'default'是父进程)...哦。并测试'execlp',而你在...;-) – Myst

+0

另外,在某些时候用'SIGINT'杀死孩子不是一个好主意吗? – Myst

回答

0

问题是由于发生 -

int j =0; 
while(1){ 
    if(ready){ 
     ready = 0; 
     kill(pid[j],SIGUSR1); 
     j = ((j+1)%3); 
     alarm(1); 
    } 
} 
在父进程

在这里,您初始化为j 0,并在while循环kill()中发送SIGUSR1到第一次迭代中的pid [0]。

每个信号都有一个“默认处置” - 当它接收到该信号时默认处理默认处理。

signal(7)手册页 -

SIGUSR1和SIGUSR2的默认配置是 - 期限,这就意味着终止进程。

信号值动作注释

──────────────────────────────────── ───────

SIGUSR1 30,10,16术语用户定义信号1个

SIGUSR2 31,12,17术语用户定义信号2

在你exercici儿童节目,你正在改变的信号SIGUSR1的配置和配置设置来处理函数captura_signal -

signal(SIGUSR1, captura_signal) 

在你的情况,什么情况是,与子进程PID [0]分叉时和在子进程exec执行并设置SIGUSR1信号处理程序之前,父进程将SIGUSR1发送给pid [0]。由于SIGUSR1的默认处置是终止进程,因此pid [0]子进程将终止并标记为已禁用。

在我的系统,我可以在ps命令的输出中看到 -

PS -eaf | grep的exercici

根29210 19542 86 20点51分/ 5零点00分04秒./exercici2 -------->父进程

根29211 29210 0 20 :51点/ 5 00:00:00 [exercici2] <被禁>------>子进程exec'ing exercici之前接收到的信号SIGUSR1

根29212 29210 0 20点51分/ 5 00:00:00练习----- --->子过程成功exec'ed exercici和改变SIGUSR1的默认配置

根29213 29210 0 20点51分/ 10 00:00:00 exercici -------->子进程成功exec'ed exercici和SIGUSR1

在这里你可以看到PID 29211的第一个孩子的过程被标记为解散的更改的默认配置。

你可以通过各种方式解决这个问题。其中之一是简单地通过增加这种说法忽略SIGUSR1在父进程 - 在分叉子进程的父进程的开始

signal(SIGUSR1,SIG_IGN); 

地方。

子进程从父进程继承信号处理程序。因此,在使用新进程(exercici)执行当前进程映像之前,如果子进程接收到SIGUSR1,它将忽略它。

+0

我见过的最详细的答案。非常感谢。 –

0

这是有点棘手理解fork()和子进程的创建和其中的代码,子进程将执行部分。在这里你从每个子进程调用while(1)循环,那部分代码不在主进程中执行,而只在子进程内执行。因此'j'总是0,你实际上执行的是kill(pid [0],SIGUSR1); ( 3次)。

从父进程控制子进程总是更好。请参阅下面的修改后的代码,它适用于您。

int parentPID = 0; 

int main(int argc, char *argv[]){ 
int pid[3]; 
parentPID = getpid(); 
signal(SIGALRM,sigAlarm); 
for(int i = 0; i<3;i++){ 
    if((pid[i]=fork()) == 0){ 
     printf("child :%d\n",i); 
     execlp("./exercici","exercici",(char*)NULL); 
    } 
} 
if (parentPID == getpid()){ 
    sleep(5);/* Let the 3 childs create */ 
    int j = 0; 
    int ready = 1; 
    while(ready){ 
     kill(pid[j],SIGUSR1); 
     j = ((j+1)%3); 
     ready = j; 
     alarm(1); 
    } 
    } 

}