C、fork和exec进程,并发送信号
C, Fork and exec process, and sending signals
基本上我有两个代码。
其中之一必须在每次收到 SIGUSR1 信号时打印 shell "TIME!"。
我们称它为 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();
}
}
另一个,必须创建三个 child 进程(只有一个 parent 和三个 child)并在每个 child 上执行 execlp exercici.c。
然后,每一秒,parent 必须向一个 child 发送一个 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
理解 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);
}
}
}
问题的发生是因为-
int j =0;
while(1){
if(ready){
ready = 0;
kill(pid[j],SIGUSR1);
j = ((j+1)%3);
alarm(1);
}
}
在父进程中。
在这里你用 0 初始化 j
并且在 while 循环 kill() 中发送 SIGUSR1
到 pid[0] 在第一次迭代中。
每个信号都有一个 "default disposition" -- 进程在收到该信号时默认执行的操作。
来自 signal(7) 手册页 -
SIGUSR1 和 SIGUSR2 默认配置是 - Term,这意味着终止进程。
Signal Value Action Comment
───────────────────────────────────────────
SIGUSR1 30,10,16 Term User-defined signal 1
SIGUSR2 31,12,17 Term User-defined signal 2
在您的 exercici 子程序中,您正在更改信号 SIGUSR1 的配置并将配置设置为处理函数 captura_signal
-
signal(SIGUSR1, captura_signal)
在你的例子中,发生的事情是当分叉时具有 pid[0] 的子进程在子进程执行并设置 SIGUSR1 信号处理程序之前,父进程将 SIGUSR1 发送到 pid[0]。由于 SIGUSR1 的默认配置是终止进程,因此 pid[0] 子进程被终止并标记为 defunct。
在我的系统上,我可以在 ps 命令的输出中看到 -
ps-eaf | grep 练习
root 29210 19542 86 20:51 pts/5 00:00:04 ./exercici2 -------->父进程
root 29211 29210 0 20:51 pts/5 00:00:00 [exercici2] ------> 收到子进程在执行 execcici
之前发出信号 SIGUSR1
root 29212 29210 0 20:51 pts/5 00:00:00 exercici --------> 子进程成功执行练习并更改 SIGUSR1
的默认配置
root 29213 29210 0 20:51 pts/5 00:00:00 exercici --------> 子进程成功执行练习并更改 SIGUSR1
的默认配置
在这里你可以看到 pid 为 29211 的第一个子进程被标记为 defunct.
您可以通过多种方式解决这个问题。其中之一是通过添加此语句 -
来简单地忽略父进程中的 SIGUSR1
signal(SIGUSR1,SIG_IGN);
在父进程开始分叉子进程的某处。
子进程从父进程继承信号处理程序。因此,在使用新进程 (execcici) 执行当前进程映像之前,如果子进程收到 SIGUSR1,它将忽略它。
基本上我有两个代码。 其中之一必须在每次收到 SIGUSR1 信号时打印 shell "TIME!"。 我们称它为 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();
}
}
另一个,必须创建三个 child 进程(只有一个 parent 和三个 child)并在每个 child 上执行 execlp exercici.c。 然后,每一秒,parent 必须向一个 child 发送一个 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
理解 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);
}
}
}
问题的发生是因为-
int j =0;
while(1){
if(ready){
ready = 0;
kill(pid[j],SIGUSR1);
j = ((j+1)%3);
alarm(1);
}
}
在父进程中。
在这里你用 0 初始化 j
并且在 while 循环 kill() 中发送 SIGUSR1
到 pid[0] 在第一次迭代中。
每个信号都有一个 "default disposition" -- 进程在收到该信号时默认执行的操作。
来自 signal(7) 手册页 -
SIGUSR1 和 SIGUSR2 默认配置是 - Term,这意味着终止进程。
Signal Value Action Comment
───────────────────────────────────────────
SIGUSR1 30,10,16 Term User-defined signal 1
SIGUSR2 31,12,17 Term User-defined signal 2
在您的 exercici 子程序中,您正在更改信号 SIGUSR1 的配置并将配置设置为处理函数 captura_signal
-
signal(SIGUSR1, captura_signal)
在你的例子中,发生的事情是当分叉时具有 pid[0] 的子进程在子进程执行并设置 SIGUSR1 信号处理程序之前,父进程将 SIGUSR1 发送到 pid[0]。由于 SIGUSR1 的默认配置是终止进程,因此 pid[0] 子进程被终止并标记为 defunct。
在我的系统上,我可以在 ps 命令的输出中看到 -
ps-eaf | grep 练习
root 29210 19542 86 20:51 pts/5 00:00:04 ./exercici2 -------->父进程
root 29211 29210 0 20:51 pts/5 00:00:00 [exercici2]
root 29212 29210 0 20:51 pts/5 00:00:00 exercici --------> 子进程成功执行练习并更改 SIGUSR1
的默认配置root 29213 29210 0 20:51 pts/5 00:00:00 exercici --------> 子进程成功执行练习并更改 SIGUSR1
的默认配置在这里你可以看到 pid 为 29211 的第一个子进程被标记为 defunct.
您可以通过多种方式解决这个问题。其中之一是通过添加此语句 -
来简单地忽略父进程中的 SIGUSR1signal(SIGUSR1,SIG_IGN);
在父进程开始分叉子进程的某处。
子进程从父进程继承信号处理程序。因此,在使用新进程 (execcici) 执行当前进程映像之前,如果子进程收到 SIGUSR1,它将忽略它。