C forks and processes,“为什么需要这个?

C forks and processes, ¿Why its necessary this?

我是学C的,一直在尝试做一个简单的测试程序。问题是我有一个问题是通过我不理解的方式解决的。这是我的程序:

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <signal.h>

void trat1(int s){
    signal(SIGALRM, trat1);
}
void trat2(int s){
    signal(SIGALRM, trat2);
}

int main( void ) {
    int statusHijo1, statusHijo2;
    int hijo1, hijo2;
    int hijoFinalizado, status;
    statusHijo1 =0;
    statusHijo2 = 0;

    if((hijo1 = fork()) == 0){
        /* Hijo 1 */

        printf("-- Hijo1 PID:%d | Parent PID:%d", getpid(), getppid());
        printf("\n -- Hijo1 Lanzando SIGTERM -- \n");
        while(1){
            signal(SIGALRM, trat2);
            alarm(1);
            pause();
            printf("  -- Hijo1 awaitting 1 sec.. \n");
        }
    } 
    else{
        if ( (hijo2=fork()) == 0 ) { 
            /* Hijo 2 */

                printf("++ Hijo2 PID:%d | Parent PID:%d \n", getpid(), getppid());
                signal(SIGALRM, trat2);
                alarm(5);
                pause();
                kill(hijo1, SIGKILL); 
                printf("++ Hijo2 Sending Kill signal to Hijo1\n");
                printf("++ Proceso Hijo2 terminado\n");
        } 
        else{
            /* Padre */

            do{
                hijoFinalizado = wait(&status); //El hijo finalizado es el que cambia el estado del programa
                if(hijoFinalizado == hijo1) statusHijo1 = 1;
                else if(hijoFinalizado == hijo2) statusHijo2 = 1;

            }while(!statusHijo1 || !statusHijo2);
            printf("\n** Soy el padre con PID: %d y he terminado \n", getpid());

        }   
    }

}

这个程序很简单,父亲在等他的两个孩子,1会等5秒,直到第二个杀死它。

这里是控制台的输出:

-- Hijo1 PID:29793 | Parent PID:29792
 -- Hijo1 Lanzando SIGTERM -- 
++ Hijo2 PID:29794 | Parent PID:29792 
  -- Hijo1 awaitting 1 sec.. 
  -- Hijo1 awaitting 1 sec.. 
  -- Hijo1 awaitting 1 sec.. 
  -- Hijo1 awaitting 1 sec.. 
++ Hijo2 Sending Kill signal to Hijo1
++ Proceso Hijo2 terminado

** Soy el padre con PID: 29792 y he terminado 

问题是我不知道 hijoFinalizado = wait(&status); 是如何工作的,因为没有它程序就无法运行。 这是没有它的情况:

-- Hijo1 PID:1547 | Parent PID:1546
 -- Hijo1 Lanzando SIGTERM -- 
++ Hijo2 PID:1548 | Parent PID:1546 
  -- Hijo1 awaitting 1 sec.. 
  -- Hijo1 awaitting 1 sec.. 
  -- Hijo1 awaitting 1 sec.. 
  -- Hijo1 awaitting 1 sec.. 
++ Hijo2 Sending Kill signal to Hijo1
++ Proceso Hijo2 terminado

然后卡在这里。

¿为什么我没有声明的变量是决定进程是否完成的变量?

¿ 为什么 while( (wait(&statusHijo1)!=hijo1)&& (wait(&statusHijo2)!=hijo2) ) ; 不正确? 这是这样做的结果:

-- Hijo1 PID:1148 | Parent PID:1147
++ Hijo2 PID:1149 | Parent PID:1147 
 -- Hijo1 Lanzando SIGTERM -- 
  -- Hijo1 awaitting 1 sec.. 
  -- Hijo1 awaitting 1 sec.. 
  -- Hijo1 awaitting 1 sec.. 
  -- Hijo1 awaitting 1 sec.. 
++ Hijo2 Sending Kill signal to Hijo1
++ Proceso Hijo2 terminado

然后卡在这里。

[加法]

¿trat1 和 trat2 的真正功能是什么?我知道它们很重要,但我不知道为什么。

对不起我的英语,非常感谢。

Why a variable that I dont declare is the one who decides if a process has finished?

你是说status?你声明它;你只是不初始化它。这很好,因为 wait 不读它; wait 填充它。换句话说,它不是输入;这是一个输出。

wait 等待 child 完成。它 returns 进程的 PID,并将 status 设置为 child 的退出状态。

您可以使用状态如下:

if (WIFSTOPPED(status)) {
   printf("Child killed by signal %d\.n", WSTOPSIG(status));
}
else if (WEXITSTATUS(status)) {
   printf("Child exited with error %d.\n", WEXITSTATUS(status));
}
else {
   printf("Child completed successfully.\n", WEXITSTATUS(status));
}

仅回答附加问题

实施

while( (wait(&statusHijo1)!=hijo1)&& (wait(&statusHijo2)!=hijo2) ) ; 

是错误的,因为您不能 wait 仅针对特定的 child。 (为此您需要 waitpid,但您必须确保在您的代码中指定的 child 能够终止。)

您可以遍历代码并思考会发生什么。

示例:

假设 child 1 在 child 2 之前终止。

第一个wait(&statusHijo1)将child1的状态保存到statusHijo1,returnchild1的PID和条件!=hijo1 将为假。

作为逻辑与的结果,所以不会调用第二个wait(&statusHijo2)而终止循环。你的程序不会等待child2,statusHijo2不变。

假设 child 2 在 child 1 之前终止。

第一个wait(&statusHijo1)将child2的状态保存到statusHijo1,returnchild2的PID和条件!=hijo1 将为真,因此它将调用第二个 wait(&statusHijo2)

这会将 child 1 的状态保存到 statusHijo2,return child 1 的 PID,并且条件 !=hijo2 将为真。 循环将重复,因为两个条件都为真。

它将再次调用 wait(&statusHijo1),这将 return -1 因为您没有 child 等待。条件 !=hijo1 将为真,它将调用 wait(&statusHijo2), return -1 并且条件 !=hijo2 将为真,因此它将再次重复循环。

在这种情况下你会得到一个无限循环。


trat1trat2SIGALRM 的信号处理函数。他们只做 re-establish 自己。 signal() 的实现因不同的 UNIX 系统而异。在某些系统上,接收信号会将信号处理程序重置为默认值,因此信号处理程序必须再次调用 signal()

没有信号处理程序,信号 SIGALRM 将终止进程。

代替signal(SIGALRM, trat2); alarm(5); pause();你也可以使用sleep(5);.