【问题标题】:Exec To Another Program + Child Death执行到另一个程序 + 儿童死亡
【发布时间】:2013-10-14 18:02:20
【问题描述】:

我正在尝试编写一个程序,根据用户输入值“n”,我将分叉那么多进程以同时运行。此外,每个孩子都试图执行到我创建的另一个文件,这将生成 x 睡眠时间和 x 退出值。最终,当孩子死亡时,父母需要打印 pid 和 exit_status。重要的部分是确保儿童死亡是 x,而不是同时发生。到目前为止,有两件事我无法弄清楚。

  1. 让我的 execl 运行我的 sleep.c 文件(如下所示)。
  2. 让孩子们随机分叉和死亡,而不是以有序的方式,结果打印谁死了,他们生成的随机退出状态。

我有两个文件,Sleep.c 和 Ranchild.c。

睡眠.C

#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <time.h>

/* Generated random sleep time, and return random exit value */

int main()
{
    /* Calculate A Random Time To Sleep 1 - 10 Seconds*/
    srand(time(NULL));
    int r = (rand() % 10) + 1;

    printf("Sleep Time: %d\n", r);
    sleep(r);

    /* Calculate A Random Exit Value */
    int r2 = (rand() % 30) + 1;
    exit(r2);       
}

RANCHILD.C

#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <time.h>

int main()
{
    /* Get User Input */
    int i, n;

    printf("Please Enter An Integer!\n");

    /* Test User Input */
    if(!scanf("%d", &n)) {
        printf("Invalid Input!\n");
        return -1;
    }   

    /* Initialize Needed Variables */
    pid_t pid[n];
    int status, exit_status;

    for(i = 0; i < n; i++) {

        if((pid[i] = fork()) < 0) {
            perror("Fork Failed!");
            return -2;
        }

        if(pid[i] == 0) {
            execl("sleep", "sleep", (char *)0);
} else {
    /* Print Child Results */
    if (waitpid(-1, &status, WNOHANG) == 0) {
        if(WIFEXITED(status)) {
            exit_status = WEXITSTATUS(status);
            printf("Exit Status From %d was %d!\n", pid[i], exit_status);
        }
    }   

}       
    }

    exit(0);
}

它永远不会执行到睡眠文件,结果示例如下:

3
Exit Status From 27369 was 0!
Exit Status From 27370 was 0!
Exit Status From 27371 was 0!
Sleep Time: 4
Sleep Time: 4
Sleep Time: 4

非常感谢您的帮助!!

【问题讨论】:

  • 在调用wait 之前,您无法检查status 的值。我没有看到对 wait 的呼叫。
  • 我加了等待,结果还是0 =[ 可能是我加错了?不管状态如何,孩子们仍在同时死亡。
  • 他们正在同时死亡,因为您可能在检查状态的“其他”中等待他们。您将阻止 wait 并因此在循环中一次创建一个孩子。
  • sleep.c代码中,由于子进程都可能同时启动(同一秒),使用time()播种srand()不太可能正常工作。也使用getpid();保证是唯一的。您还可以使用亚秒计时函数之一(例如clock_gettime()gettimeofday())结果的亚秒部分。但是在多CPU芯片上,PID还是唯一的,时间也不一定唯一。当然,退出状态也有同样的问题;所有孩子都可能以相同的状态退出。
  • 您需要围绕waitpid() 调用而不仅仅是if。并且整个等待工作应该在您创建所有孩子之后完成,而不是在您创建每个孩子之后。

标签: c linux unix fork


【解决方案1】:

建议这样的事情。乔纳森是对的。你需要更好的东西来播种rand。孩子们跑得如此之快,以至于他们很可能都以相同的睡眠时间和退出代码结束。

int ret;

for (i = 0; i < n; i++)
{

    if ((pid[i] = fork()) < 0)
    {
        perror("Fork Failed!");
        return -2;
    }

    if (pid[i] == 0)
    {
        if ((ret = execl("sleep", "sleep", (char *)0)) == -1)
        {
            perror("execl");
            exit(1);
        }
    }
}

for (i = 0; i < n; i++)
{
   if (wait(&status) == -1)
   {
      perror("wait"); exit(1);
   }

   if (WIFEXITED(status))
   {
       exit_status = WEXITSTATUS(status);
       printf("Exit Status From %d was %d!\n", pid[i], exit_status);
   }
}

子/执行程序

#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <time.h>
#include <math.h>

/* Generated random sleep time, and return random exit value */

void getRandomNumbers(int *r1, int *r2)
{
    int fd;

    if (((fd = open("/dev/urandom", O_RDONLY))) == -1)
    { perror("open"); exit(1);}

    read(fd, r1, sizeof(int));
    read(fd, r2, sizeof(int));
    close(fd);

    return;
}

int main()
{
    int r1 = 0, r2 = 0;

    getRandomNumbers(&r1, &r2);

    int sleeptime = abs((r1 % 10)) + 1;

    printf("Sleep Time: %d\n", sleeptime);
    sleep(sleeptime);

    int exitcode = abs((r2 % 30)) + 1;

    exit(exitcode);
}

【讨论】:

  • 这很好地涵盖了主程序和等待循环。您还没有(尚未)解决儿童行为中(缺乏)随机性的问题——哦,好的,您刚刚简要介绍了它。
  • 其实我想出了和你一样的 - 使用getpid()。我不认为需要展示。
  • 谢谢。有用!我在 srand 中使用了 getpid()。美女,谢谢!
  • 等等,我刚刚意识到,他们还在同时死亡。有没有办法随机化他们的死亡?还是根本不可能?
  • 是的,我以为你可能会抢先一步。我也在努力让这个随机化。我正在努力想一些不太复杂的事情。
【解决方案2】:

sleep.c

#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <time.h>

/* Generated random sleep time, and return random exit value */
int main(int argc, char **argv)
{
    int seed = time(0);
    if (argc > 1)
        seed = atoi(argv[1]);
    srand(seed);

    int r = (rand() % 10) + 1;
    int r2 = (rand() % 30) + 1;

    printf("%d: Seed: %d; Sleep: %d; Exit %d\n", (int)getpid(), seed, r, r2);

    sleep(r);
    exit(r2);       
}

ranchild.c

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

int main(int argc, char **argv)
{
    int n = 10;
    if (argc > 1)
        n = atoi(argv[1]);
    if (n <= 0)
    {
        fprintf(stderr, "%s: invalid number of processes %d\n", argv[0], n);
        return(1);
    }

    int i;
    pid_t pid[n];
    int t = time(0);
    srand(t);

    printf("Time/seed: %d\n", t);

    for (i = 0; i < n; i++)
    {
        int seed = rand();
        fflush(0);
        if ((pid[i] = fork()) < 0)
        {
            fprintf(stderr, "%s: Fork Failed!\n", argv[0]);
            return -2;
        }
        if (pid[i] == 0)
        {
            const char command[] = "sleep";
            char argument[15];
            snprintf(argument, sizeof(argument), "%d", seed);
            execl(command, command, argument, (char *)0);
            fprintf(stderr, "%d: failed to execute %s\n", (int)getpid(), command);
            return(1);
        }
        printf("Child: %d (%d)\n", pid[i], seed);
    }

    int corpse, status;
    while ((corpse = waitpid(-1, &status, 0)) > 0)
    {
        if (WIFEXITED(status))
            printf("%d: Exit Status From %d was %d!\n",
                   (int)time(0), corpse, WEXITSTATUS(status));
        else
            printf("%d: Exit status from %d was 0x%.4X\n",
                   (int)time(0), corpse, status);
    }

    return(0);
}

样本输出

Time/seed: 1381199552
Child: 66443 (1670130041)
Child: 66444 (116849150)
Child: 66445 (1083610692)
Child: 66446 (1583573884)
Child: 66447 (1361431117)
Child: 66448 (134524634)
Child: 66449 (1802726994)
Child: 66450 (1733296282)
Child: 66451 (894940019)
66443: Seed: 1670130041; Sleep: 1; Exit 13
66452: Seed: 281435745; Sleep: 2; Exit 11
66444: Seed: 116849150; Sleep: 3; Exit 5
66449: Seed: 1802726994; Sleep: 3; Exit 30
66447: Seed: 1361431117; Sleep: 5; Exit 25
66445: Seed: 1083610692; Sleep: 5; Exit 8
66448: Seed: 134524634; Sleep: 5; Exit 23
66451: Seed: 894940019; Sleep: 6; Exit 22
66446: Seed: 1583573884; Sleep: 8; Exit 15
66450: Seed: 1733296282; Sleep: 10; Exit 16
Child: 66452 (281435745)
1381199553: Exit Status From 66443 was 13!
1381199554: Exit Status From 66452 was 11!
1381199555: Exit Status From 66444 was 5!
1381199555: Exit Status From 66449 was 30!
1381199557: Exit Status From 66447 was 25!
1381199557: Exit Status From 66445 was 8!
1381199557: Exit Status From 66448 was 23!
1381199558: Exit Status From 66451 was 22!
1381199560: Exit Status From 66446 was 15!
1381199562: Exit Status From 66450 was 16!

【讨论】:

  • 我早些时候犯了一个愚蠢的错误,但srand(getpid()); 似乎也可以工作,这可以避免上述很多情况。
  • 所以它 (srand(getpid())) 应该可以工作!它将避免上述一些,但不如所有这些:事实上,它节省了 80 行中的 8 行,给或取奇数空行,或大约 10%。我的解决方案中的一些额外代码显示了儿童死亡之间经过的时间。您应该能够跟踪孩子们所说的他们将在何时以及如何在父母看到的情况下死去。
猜你喜欢
  • 2016-03-15
  • 2010-10-10
  • 2023-03-21
  • 2019-07-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-02-22
  • 1970-01-01
相关资源
最近更新 更多