【问题标题】:C forks and processes, ¿Why its necessary this?C 分叉和进程,¿为什么需要这个?
【发布时间】:2019-11-25 18:33:35
【问题描述】:

我正在学习 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(&amp;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(&amp;statusHijo1)!=hijo1)&amp;&amp; (wait(&amp;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 的真正作用是什么?我知道它们很重要,但我不知道为什么。

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

【问题讨论】:

  • wait() 等待任何进程,返回值告诉您哪个进程更改了其状态或是否发生错误。要仅等待特定的子进程,您可以使用waitpid,但即使预期运行时间不同,您也不能绝对确定哪个进程首先终止,因此等待任何子进程是实现此目的的正确方法。 “没有它,程序不起作用”到底是什么意思?发生什么或不发生什么?请edit您的问题澄清这一点,不要在 cmets 中回答。
  • @Bodo 非常感谢您的解释,它对我帮助很大。我已经更新了我的问题并添加了另一个问题。
  • 请展示源代码(相关部分)在没有wait的版本中的样子。

标签: c process signals child-process


【解决方案1】:

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

你的意思是status?你确实声明它;你根本不初始化它。这很好,因为wait 不阅读它; wait 填充它。换句话说,它不是输入;这是一个输出。

wait 等待孩子完成。它返回进程的 PID,并将status 设置为子进程的退出状态。

您可以使用如下状态:

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

【讨论】:

  • 所以wait是初始化变量status,并将子pid插入到status中,¿No?
  • @Ibai wait 不会将子 PID 插入到 status。如果一个孩子改变了它的状态,wait 会将状态写入变量并使用 PID 作为返回值。正返回值始终是 PID。
【解决方案2】:

仅回答其他问题

实现

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

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

您可以浏览代码并考虑会发生什么。

例子:

假设孩子 1 在孩子 2 之前终止。

第一个wait(&amp;statusHijo1)会将child 1的状态保存到statusHijo1,返回child 1的PID,条件!=hijo1为false。

由于逻辑与的结果,所以它不会调用第二个wait(&amp;statusHijo2) 并终止循环。您的程序不会等待孩子 2,statusHijo2 将保持不变。

假设孩子 2 在孩子 1 之前终止。

第一个wait(&amp;statusHijo1)会将孩子2的状态保存到statusHijo1,返回孩子2的PID,条件!=hijo1为真,所以它会调用第二个wait(&amp;statusHijo2)

这会将孩子1的状态保存到statusHijo2,返回孩子1的PID,条件!=hijo2将为真。 循环将重复,因为这两个条件都为真。

它会再次调用wait(&amp;statusHijo1),它会返回-1,因为你没有孩子要等待。条件!=hijo1为真,它会调用wait(&amp;statusHijo2),返回-1,条件!=hijo2为真,所以它会再次重复循环。

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


trat1trat2SIGALRM 的信号处理函数。他们无非是重新建立自己。 signal() 的实现在不同的 UNIX 系统之间有所不同。在某些系统上,接收到信号会将信号处理程序重置为默认值,因此信号处理程序必须再次调用signal()

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

您也可以使用sleep(5);,而不是signal(SIGALRM, trat2); alarm(5); pause();

【讨论】:

    猜你喜欢
    • 2015-05-20
    • 1970-01-01
    • 1970-01-01
    • 2010-12-15
    • 1970-01-01
    • 2011-05-10
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多