基本上我有两个代码。 其中一个必须在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]一个。
答案 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 。
您可以通过各种方式解决此问题。其中之一是通过添加此语句 -
来简单地忽略父进程中的SIGUSR1signal(SIGUSR1,SIG_IGN);
在父进程开始分配子进程的某个地方。
子进程从父进程继承信号处理程序。因此,在使用新进程(exercici)执行当前进程映像之前,如果子进程收到SIGUSR1,它将忽略它。