【问题标题】:Sleep() causing broken pipe?睡眠()导致管道破裂?
【发布时间】:2020-03-12 01:36:37
【问题描述】:

所以在大学里我现在正在学习并发编程。我在管道上做练习,有以下几点:

编写一个程序,创建 10 个子进程来玩“赢得管道!”游戏。 必须只有一个管道,由所有进程共享。游戏规则如下: 父进程每 2 秒填充一个带有“Win”消息和回合数(1 到 10)的结构,并将此数据写入管道;每个子进程都试图从管道中读取数据。成功的孩子应该打印获胜信息和轮数,并以等于获胜轮数的退出值结束执行;剩下的子进程继续尝试从管道中读取数据;在所有子进程终止后,父进程应该打印每个子进程的 PID 和获胜回合。

我有以下代码:

#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <sys/wait.h>

struct Something {
    char message[4];
    char round;
};

int main() {
    int fd[2];
    pid_t pid;
    struct Something something;
    int status;

    if (pipe(fd) == -1) {
        perror("error creating pipe");
        return 1;
    }

    for (int i = 0; i < 10; ++i) {
        pid = fork();
        if (pid == 0) { break; }
    }

    if (pid > 0) { //parent
        close(fd[0]);
        while (something.round <= 10) {
            //sleep(2);  PROBLEM HERE
            strcpy(something.message, "Win");
            something.round++;
            write(fd[1], &something, sizeof(something));
        }
        close(fd[1]);
        for (int i = 0; i < 10; ++i) {
            pid = wait(&status);
            printf("PID: %d  won round %d\n", pid, WEXITSTATUS(status));
        }
    } else { //child
        close(fd[1]);
        read(fd[0], &something, sizeof(something));
        close(fd[0]);
        printf("%s %d", something.message, something.round);
        _exit(something.round);
    }

    return 0;
}

所以当我没有 sleep() 注释并运行程序时,会发生什么情况是它冻结并且没有打印任何内容,并且子进程会一个接一个地慢慢完成,然后我会收到损坏的管道消息。

但是当我评论 sleep() 时,程序运行得很好,虽然父级没有等待 2 秒,并且我想只是填满了管道。 我无法理解这个问题,并且一直在寻找答案,但没有成功。

如果我能对此有所启发,我将不胜感激。

【问题讨论】:

  • while (something.round &lt;= 10) { 你从未初始化过something.round
  • 尝试在子输出的末尾打印一个换行符。
  • @Barmar 是的,但它实际上假定值为 0 并且仍然按预期工作。可能不是一个好习惯,但我想我可以把它留给练习
  • 绝对不是,你应该总是初始化你的变量。
  • stdout 在写入终端时被行缓冲。

标签: c linux posix


【解决方案1】:

问题出在你的循环中。

  while (something.round <= 10) {
            //sleep(2);  PROBLEM HERE
            strcpy(something.message, "Win");
            something.round++;

将迭代 11 次。

试试something.round &lt; 10

另外,要么刷新子级中的标准输出,要么调用 exit 而不是 _exit

【讨论】:

    猜你喜欢
    • 2013-05-24
    • 2017-07-31
    • 2011-07-19
    • 1970-01-01
    • 2011-09-23
    • 2021-12-07
    • 2021-04-12
    • 1970-01-01
    相关资源
    最近更新 更多