C,Fork和exec处理,并发送信号

时间:2017-10-11 10:21:39

标签: c signals fork exec

基本上我有两个代码。 其中一个必须在shell中打印“TIME!”每次收到SIGUSR1信号。 我们称之为exercici.c

#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个进程,我只接收TIME!其中2个。它会跳过pid [0]一个。

shell image

2 个答案:

答案 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);
     }
    }

}

答案 1 :(得分: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]。

每个信号都有一个&#34;默认配置&#34; - 当接收到该信号时,默认情况下进程的作用。

来自signal(7)手册页 -

SIGUSR1和SIGUSR2默认处置是 - Term ,这意味着终止进程。

  

信号值行动评论

     

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

     

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

     

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

exercici 子程序中,您正在更改信号SIGUSR1的处置并将处置设置为处理函数captura_signal -

 signal(SIGUSR1, captura_signal)

在你的情况下,发生的事情是子进程在分叉时和子进程执行exec并设置SIGUSR1信号处理程序之前使用pid [0],父进程将SIGUSR1发送到pid [0]。由于SIGUSR1的默认处置是终止进程,因此pid [0]子进程终止并标记为已失效。

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

ps -eaf | grep exercici

root 29210 19542 86 20:51 pts / 5 00:00:04 ./exercici2 --------&gt;家长流程

root 29211 29210 0 20:51 pts / 5 00:00:00 [exercici2]&lt;已解散&gt;的 ------&GT;子进程在执行练习之前收到信号SIGUSR1

root 29212 29210 0 20:51 pts / 5 00:00:00 exercici --------&gt;子进程成功执行了execi并更改了SIGUSR1的默认处置

root 29213 29210 0 20:51 pts / 5 00:00:00 exercici --------&gt;子进程成功执行了execi并更改了SIGUSR1的默认处置

在这里,您可以看到第一个带有pid 29211的子进程被标记为 defunct

您可以通过各种方式解决此问题。其中之一是通过添加此语句 -

来简单地忽略父进程中的SIGUSR1
signal(SIGUSR1,SIG_IGN);

在父进程开始分配子进程的某个地方。

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