【问题标题】:Child process sends a number through a pipe, then waits子进程通过管道发送一个数字,然后等待
【发布时间】:2017-03-30 14:34:15
【问题描述】:

我正在尝试生成两个通过管道连接的子进程。 孩子 1 应该通过管道向孩子 2 发送一个数字,孩子 2 应该打印它。我设法做到了,但是当我尝试循环执行此操作时,孩子 1 每次在发送另一个号码之前等待 1 秒,它不会发送任何内容。
我做错了什么?

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <signal.h>
#include <windows.h>

int main(int argc, char *argv[]) {
    int fd[2];
    pipe(fd);
    pid_t pid1 = fork();
    if (pid1) {
        pid_t pid2 = fork();
        if (pid2) { //parent
            // do stuff as parent
        } else { //child 2
            close(fd[1]);
            char stringNumberReceived[10];
            while (1) {
                read(fd[0], stringNumberReceived, sizeof (stringNumberReceived));
                printf("number received: %s\n", stringNumberReceived);
            }
        }
    } else {//child 1
        close(fd[0]);
        int num;
        char stringnumber [10];
        while (1) {
            num = rand();
            snprintf(stringnumber, 10, "%d", num);
            printf("attempting to sent: %s\n", stringnumber);
            write(fd[1], stringnumber, strlen(stringnumber) + 1);
            Sleep(1000);
        }
    }
}

【问题讨论】:

  • 您可以从检查write read 返回的内容开始。如果他们返回 -1 失败,您需要检查 errno 以查看问题所在(例如使用 perror 将其打印出来)。另外,如果read return 0 表示管道的另一端已关闭,请也检查一下。
  • 您还应该为pipefork 调用添加错误检查。 close 函数可能失败,但是在传递正确的描述符时发生这种情况的可能性很小,所以通常不检查那个是可以的。
  • 好的,我试过了,还检查了管道和叉子调用是否成功,我稍微更改了代码。输出:尝试发送:148176593 收到号码:148176593 尝试发送:108537774 运行成功(总时间:1s)。问题是写入功能失败并且当我尝试第二次发送号码时不返回任何内容。如果我在没有 Sleep(1000) 的情况下执行此操作,则 write() 会设法发送一堆数字,但一旦读取第一个数字,程序就会停止。

标签: c pipe sleep


【解决方案1】:

这是您的代码的轻微修改版本:

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

enum { MAX_COUNT = 20 };

int main(void)
{
    int fd[2];
    pipe(fd);
    pid_t pid1 = fork();
    if (pid1)
    {
        pid_t pid2 = fork();
        if (pid2)   // parent
        {
            printf("Child 1: %d; child 2: %d\n", (int)pid1, (int)pid2);
            close(fd[0]);   // Let the child detect EOF!
            close(fd[1]);   // Let the child detect EOF!
            int corpse;
            int status;
            while ((corpse = wait(&status)) > 0)
                printf("PID %d exited with status 0x%.4X\n", corpse, status);
        }
        else     // child 2
        {
            close(fd[1]);
            char stringNumberReceived[10];
            int nbytes;
            while ((nbytes = read(fd[0], stringNumberReceived, sizeof(stringNumberReceived))) > 0)
                printf("number received: %.*s\n", nbytes, stringNumberReceived);
            printf("Child 2: EOF or ERR\n");
        }
    }
    else    // child 1
    {
        close(fd[0]);
        int num;
        char stringnumber[10];
        for (int counter = 0; counter < MAX_COUNT; counter++)
        {
            num = rand();
            snprintf(stringnumber, sizeof(stringnumber), "%d", num);
            printf("attempting to send: [%s] (len %zu)\n", stringnumber, strlen(stringnumber));
            write(fd[1], stringnumber, strlen(stringnumber) + 1);
            sleep(1);
        }
    }
    return 0;
}

发生了什么变化?各种东西。您可以忽略大括号位置的变化;这纯粹是装饰性的。

  1. 父代码已实现。
  2. 父进程报告子进程 ID。
  3. 父级关闭管道 - 既不读取也不写入。
  4. 父母等待孩子死亡,同时报告他们的状态。
  5. Child 记录它读取的字节数,并确保它打印的字节数不超过该字节数。
  6. 当管道出现错误或 EOF(读取 0 字节)时,它会终止循环并在退出前报告。
  7. 其他孩子在退出前进行了固定数量的循环(如图所示,为 20 个)。
  8. 如果随机数生成器曾经生成过 10 位以上的数字,您可能会遇到数组边界问题。我得到的最大长度是 9,这很安全。
  9. 生成孩子可以/应该在完成后报告。

在这些变化中,我怀疑关闭父管道中的管道可能是关键。

示例输出(在 Unix 机器上):

$ pp43
attempting to send: [16807] (len 5)
Child 1: 69198; child 2: 69199
number received: 16807
attempting to send: [282475249] (len 9)
number received: 282475249
attempting to send: [162265007] (len 9)
number received: 162265007
attempting to send: [984943658] (len 9)
number received: 984943658
attempting to send: [114410893] (len 9)
number received: 114410893
attempting to send: [470211272] (len 9)
number received: 470211272
attempting to send: [101027544] (len 9)
number received: 101027544
attempting to send: [145785087] (len 9)
number received: 145785087
attempting to send: [145877792] (len 9)
number received: 145877792
attempting to send: [200723770] (len 9)
number received: 200723770
attempting to send: [823564440] (len 9)
number received: 823564440
attempting to send: [111543816] (len 9)
number received: 111543816
attempting to send: [178448449] (len 9)
number received: 178448449
attempting to send: [74243042] (len 8)
number received: 74243042
attempting to send: [114807987] (len 9)
number received: 114807987
attempting to send: [113752250] (len 9)
number received: 113752250
attempting to send: [144128232] (len 9)
number received: 144128232
attempting to send: [16531729] (len 8)
number received: 16531729
attempting to send: [823378840] (len 9)
number received: 823378840
attempting to send: [143542612] (len 9)
number received: 143542612
Child 2: EOF or ERR
PID 69198 exited with status 0x0000
PID 69199 exited with status 0x0000
$

【讨论】:

    猜你喜欢
    • 2022-01-16
    • 2020-06-14
    • 2016-03-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-10-09
    • 1970-01-01
    相关资源
    最近更新 更多