创建两个子进程以根据父进程的输入写入单独的文件

发布于 2025-01-10 16:35:14 字数 5631 浏览 0 评论 0原文

我需要编写一个创建两个子进程的程序。这些进程的父进程将从用户处获取数字,第一个子进程会将输入的奇数写入名为 odd.txt 的文件,而第二个子进程会将偶数写入名为 Even.txt 的文件。 (我必须利用系统调用来处理文件,而不是 fopen 等)

当用户输入 -1 时程序停止。

我的下面的代码有很多问题。虽然它允许我输入数字并在输入 -1 时停止,但文件的输出是乱码。在此处显示的示例输出中,子进程仅打印输入的第一个数字(如果是奇数,则仅打印子进程 1,反之亦然)。

示例输出 1

我也遇到了输入 0 时整个程序中断的问题,如果我尝试在 0 之后输入数字,则会出现分段错误和管道损坏。我猜这一定与 hasData 有关,但不确定如何。

输入 0 作为值会破坏事情

我真的很茫然,不知道它是什么是我做错了。任何帮助非常感谢!这是一道考试题,我没能做完。

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

int main(int argc, char const *argv[])
{
    int p1 = fork();

    // Create a pipe
    int fd[2];
    if (pipe(fd) == -1){
        printf("Could not create a pipe.");
        return 1;
    }

    if (p1 > 0){
        // Parent
        int p2 = fork();

        if (p2 > 0){
            // Parent
            close(fd[0]);

            int hasData;
            int num;

            do 
            {   printf("Enter a num: ");
                scanf("%d", &num);

                if (num == -1){
                    hasData = 0;
                    write(fd[1], &hasData, sizeof(int));
                    printf("Thanks for your numbers!");
                    close(fd[1]);    
                    exit(0);
                }

                hasData = 1;
                write(fd[1], &hasData, sizeof(int));
                write(fd[1], &num, sizeof(num));

            } while (num!= -1);      

        }
        else if (p2 == 0){
            // Second child
            sleep(1);
            close(fd[1]);         

            int hasData = 0;
            int num2;

            read(fd[0], &hasData, sizeof(int));
            read(fd[0], &num2, sizeof(int));

            int even_fd = open("even.txt", O_WRONLY | O_CREAT);

            while (hasData){
                if (num2 % 2 == 0){
                    printf("(from child 2) %d ", num2);
                    write(even_fd, &num2, sizeof(int));                
                }

                read(fd[0], &hasData, sizeof(int));
            } 

            close(even_fd);
            close(fd[0]);
        }

    } else if (p1 == 0){
        // First child
        sleep(1);
        close(fd[1]);

        int hasData = 0;
        int num1;

        read(fd[0], &hasData, sizeof(int));
        read(fd[0], &num1, sizeof(int));

        int odd_fd = open("odd.txt", O_WRONLY | O_CREAT);

        while (hasData){
            if (num1 % 2 != 0){
                printf("\n(from child 1) %d ", num1);
                write(odd_fd, &num1, sizeof(int));                
            }

            read(fd[0], &hasData, sizeof(int));
        } 

        close(odd_fd);
        close(fd[0]);
        
    }

    return 0;
}

根据评论的建议编辑代码(尽管仍然不起作用,但 0 输入现在可以正常工作,摆脱了 hasData)

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

int main(int argc, char const *argv[])
{
    // Create a pipe
    int pipe1[2];
    if (pipe(pipe1) == -1){
        printf("Could not create a pipe.");
        return 1;
    }

    int p1 = fork();

    if (p1 > 0){
        // Parent
        int pipe2[2];
        if (pipe(pipe2) == -1){
        printf("Could not create a pipe.");
        return 2;
        }

        int p2 = fork();

        if (p2 > 0){
            // Parent
            close(pipe1[0]);
            close(pipe2[0]);

            int num;

            do 
            {   printf("Enter a num: ");
                scanf("%d", &num);
                
                if (num == -1){
                    write(pipe1[1], &num, sizeof(int));
                    write(pipe2[1], &num, sizeof(int));
                    printf("\nThanks for your numbers!\n");
                    close(pipe1[1]);    
                    close(pipe2[1]); 
                    exit(0);
                }

                if(num%2 != 0){
                    // odd number
                    write(pipe1[1], &num, sizeof(num));
                } else {
                    // even number
                    write(pipe2[1], &num, sizeof(num));                   
                }
                
            } while (num!= -1);      

        }
        else if (p2 == 0){
            // Second child
            close(pipe2[1]);
            close(pipe1[0]); 
            close(pipe1[1]);          

            int num2;

            read(pipe2[0], &num2, sizeof(int));

            int even_fd = open("even.txt", O_WRONLY | O_CREAT);

            while (num2 != -1){
                printf("\n(from child 2) %d\n", num2);
                write(even_fd, &num2, sizeof(int));  
                read(pipe2[0], &num2, sizeof(int));
            } 

            close(even_fd);
            close(pipe2[0]);
        }

    } else if (p1 == 0){
        // First child
        close(pipe1[1]);

        int num1;

        read(pipe1[0], &num1, sizeof(int));

        int odd_fd = open("odd.txt", O_WRONLY | O_CREAT);

        while (num1 != -1){

            printf("\n(from child 1) %d\n", num1);
            write(odd_fd, &num1, sizeof(int));          
            read(pipe1[0], &num1, sizeof(int));
        } 

        close(odd_fd);
        close(pipe1[0]);
        
    }

    return 0;
}

I need to write a program which creates two child processes. The parent of these processes will take in numbers from the user, and the first child will write the odd numbers input to a file called odd.txt while the second child will write the even numbers to a file called even.txt. (I have to make use of system calls to work with the files and not fopen etc)

The program stops when the user inputs -1.

I'm having many issues with my code below. While it allows me to input numbers and stops when -1 is entered, the output to the files is gibberish. In the sample output shown here, the child process only prints the first number entered (if it was odd, only child 1 prints and vice-versa).

sample output 1

I also have the problem that is 0 is entered, the whole program breaks, with segmentation faults and broken pipes if I try to input numbers after the 0. I'm guessing this somehow must have to do with hasData, but not sure how.

entering 0 as a value breaks things

I'm really at a loss here, not sure what it is that I am doing wrong. Any help much appreciated thanks! This was a question for an exam which I did not manage to get to work.

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

int main(int argc, char const *argv[])
{
    int p1 = fork();

    // Create a pipe
    int fd[2];
    if (pipe(fd) == -1){
        printf("Could not create a pipe.");
        return 1;
    }

    if (p1 > 0){
        // Parent
        int p2 = fork();

        if (p2 > 0){
            // Parent
            close(fd[0]);

            int hasData;
            int num;

            do 
            {   printf("Enter a num: ");
                scanf("%d", &num);

                if (num == -1){
                    hasData = 0;
                    write(fd[1], &hasData, sizeof(int));
                    printf("Thanks for your numbers!");
                    close(fd[1]);    
                    exit(0);
                }

                hasData = 1;
                write(fd[1], &hasData, sizeof(int));
                write(fd[1], &num, sizeof(num));

            } while (num!= -1);      

        }
        else if (p2 == 0){
            // Second child
            sleep(1);
            close(fd[1]);         

            int hasData = 0;
            int num2;

            read(fd[0], &hasData, sizeof(int));
            read(fd[0], &num2, sizeof(int));

            int even_fd = open("even.txt", O_WRONLY | O_CREAT);

            while (hasData){
                if (num2 % 2 == 0){
                    printf("(from child 2) %d ", num2);
                    write(even_fd, &num2, sizeof(int));                
                }

                read(fd[0], &hasData, sizeof(int));
            } 

            close(even_fd);
            close(fd[0]);
        }

    } else if (p1 == 0){
        // First child
        sleep(1);
        close(fd[1]);

        int hasData = 0;
        int num1;

        read(fd[0], &hasData, sizeof(int));
        read(fd[0], &num1, sizeof(int));

        int odd_fd = open("odd.txt", O_WRONLY | O_CREAT);

        while (hasData){
            if (num1 % 2 != 0){
                printf("\n(from child 1) %d ", num1);
                write(odd_fd, &num1, sizeof(int));                
            }

            read(fd[0], &hasData, sizeof(int));
        } 

        close(odd_fd);
        close(fd[0]);
        
    }

    return 0;
}

Edited code following advice from comments (still doesn't work though, but 0 input works fine now, got rid of hasData)

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

int main(int argc, char const *argv[])
{
    // Create a pipe
    int pipe1[2];
    if (pipe(pipe1) == -1){
        printf("Could not create a pipe.");
        return 1;
    }

    int p1 = fork();

    if (p1 > 0){
        // Parent
        int pipe2[2];
        if (pipe(pipe2) == -1){
        printf("Could not create a pipe.");
        return 2;
        }

        int p2 = fork();

        if (p2 > 0){
            // Parent
            close(pipe1[0]);
            close(pipe2[0]);

            int num;

            do 
            {   printf("Enter a num: ");
                scanf("%d", &num);
                
                if (num == -1){
                    write(pipe1[1], &num, sizeof(int));
                    write(pipe2[1], &num, sizeof(int));
                    printf("\nThanks for your numbers!\n");
                    close(pipe1[1]);    
                    close(pipe2[1]); 
                    exit(0);
                }

                if(num%2 != 0){
                    // odd number
                    write(pipe1[1], &num, sizeof(num));
                } else {
                    // even number
                    write(pipe2[1], &num, sizeof(num));                   
                }
                
            } while (num!= -1);      

        }
        else if (p2 == 0){
            // Second child
            close(pipe2[1]);
            close(pipe1[0]); 
            close(pipe1[1]);          

            int num2;

            read(pipe2[0], &num2, sizeof(int));

            int even_fd = open("even.txt", O_WRONLY | O_CREAT);

            while (num2 != -1){
                printf("\n(from child 2) %d\n", num2);
                write(even_fd, &num2, sizeof(int));  
                read(pipe2[0], &num2, sizeof(int));
            } 

            close(even_fd);
            close(pipe2[0]);
        }

    } else if (p1 == 0){
        // First child
        close(pipe1[1]);

        int num1;

        read(pipe1[0], &num1, sizeof(int));

        int odd_fd = open("odd.txt", O_WRONLY | O_CREAT);

        while (num1 != -1){

            printf("\n(from child 1) %d\n", num1);
            write(odd_fd, &num1, sizeof(int));          
            read(pipe1[0], &num1, sizeof(int));
        } 

        close(odd_fd);
        close(pipe1[0]);
        
    }

    return 0;
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

您的好友蓝忘机已上羡 2025-01-17 16:35:14

这是我从你的代码中得出的代码。这对我有用。我也摆脱了hasData。这两个子进程基本上是对称的——我花了很长时间才发现我引入的一个不对称性。一个“主要”更改是调用输出文件 odd.bineven.bin,因为它们包含二进制数据,而不是文本(因此名称为 odd.txteven.txt 非常不合适)。使用标准 I/O(fopen()fprintf()fclose())将它们修改为文本文件将是简单而明智的。 )来写数字。另一个重要的变化是,如果输入是终端,它只会提示“Enter a num:”——当从管道或数据文件驱动时,这会更干净。

有很多诊断输出 - 部分原因是我试图找出我提到的那个令人讨厌的不对称性(这是 ==!= 的情况,正如它所发生的那样) )。父级中的信号处理也有助于跟踪。

/* SO 7130-7840 */
#include <errno.h>
#include <fcntl.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/wait.h>
#include <unistd.h>

int main(void)
{
    int odd[2];
    int even[2];

    if (pipe(odd) != 0 || pipe(even) != 0)
    {
        fprintf(stderr, "Failed to create pipes: %d %s\n", errno, strerror(errno));
        exit(EXIT_FAILURE);
    }
    pid_t p1;
    pid_t p2;


    printf("Parent: even[R] = %d, even[W] = %d, odd[R] = %d, odd[W] = %d\n",
           even[0], even[1], odd[0], odd[1]);

    if ((p1 = fork()) < 0)
    {
        fprintf(stderr, "Failed to fork 1: %d %s\n", errno, strerror(errno));
        exit(EXIT_FAILURE);
    }
    else if (p1 == 0)
    {
        /* Child 1 - odd numbers */
        printf("Child 1 at work: %5d\n", (int)getpid());
        close(even[0]);
        close(even[1]);
        close(odd[1]);
        printf("Child 1: odd[R] = %d\n", odd[0]);

        const char *filename = "odd.bin";
        int odd_fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC, 0644);
        if (odd_fd < 0)
        {
            fprintf(stderr, "Child 1: failed to open file %s: %d %s\n",
                    filename, errno, strerror(errno));
            exit(EXIT_FAILURE);
        }

        int counter = 0;
        int num1;
        int rc;
        while ((rc = read(odd[0], &num1, sizeof(num1))) == sizeof(num1))
        {
            counter++;
            if (num1 % 2 != 0)
            {
                printf("Child 1: (%d) %d\n", counter, num1);
                write(odd_fd, &num1, sizeof(num1));
            }
            else
            {
                fprintf(stderr, "Child 1: got even number %d\n", num1);
                exit(EXIT_FAILURE);
            }
        }
        if (rc < 0)
            printf("Child 1: read error (rc = %d; %d: %s)\n", rc, errno, strerror(errno));
        else
            printf("Child 1: end of loop (rc = %d)\n", rc);

        close(odd_fd);
        close(odd[0]);
        exit(EXIT_SUCCESS);
    }
    else if ((p2 = fork()) < 0)
    {
        fprintf(stderr, "Failed to fork 2: %d %s\n", errno, strerror(errno));
        exit(EXIT_FAILURE);
    }
    else if (p2 == 0)
    {
        /* Child 2 - even numbers */
        printf("Child 2 at work: %5d\n", (int)getpid());
        close(odd[0]);
        close(odd[1]);
        close(even[1]);
        printf("Child 2: even[R] = %d\n", even[0]);

        const char *filename = "even.bin";
        int even_fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC, 0644);
        if (even_fd < 0)
        {
            fprintf(stderr, "Child 2: failed to open file %s: %d %s\n",
                    filename, errno, strerror(errno));
            exit(EXIT_FAILURE);
        }

        int counter = 0;
        int num2;
        int rc;
        while ((rc = read(even[0], &num2, sizeof(num2))) == sizeof(num2))
        {
            counter++;
            if (num2 % 2 == 0)
            {
                printf("Child 2: (%d) %d\n", counter, num2);
                write(even_fd, &num2, sizeof(num2));
            }
            else
            {
                fprintf(stderr, "Child 2: got odd number %d\n", num2);
                exit(EXIT_FAILURE);
            }
        }
        if (rc < 0)
            printf("Child 2: read error (rc = %d; %d: %s)\n", rc, errno, strerror(errno));
        else
            printf("Child 2: end of loop (rc = %d)\n", rc);

        close(even_fd);
        close(even[0]);
        exit(EXIT_SUCCESS);
    }
    else
    {
        /* Parent - read and distribute */
        printf("Child 1: %5d\n", p1);
        printf("Child 2: %5d\n", p2);

        signal(SIGPIPE, SIG_IGN);   /* Writing to broken pipe gives write error */

        close(odd[0]);
        close(even[0]);

        int counter = 0;
        int num;
        while ((!isatty(STDIN_FILENO) || printf("Enter a num: ") > 0) &&
               scanf("%d", &num) == 1)
        {
            counter++;
            if (num == -1)
            {
                printf("Thanks for your %d numbers!\n", counter);
                break;
            }
            else if (num % 2 == 0)
            {
                printf("Parent - to child 2: (%d) %d\n", counter, num);
                if (write(even[1], &num, sizeof(num)) != sizeof(num))
                {
                    fprintf(stderr, "Failed to write to child 2: %d %s\n",
                            errno, strerror(errno));
                    exit(EXIT_FAILURE);
                }
            }
            else
            {
                printf("Parent - to child 1: (%d) %d\n", counter, num);
                if (write(odd[1], &num, sizeof(num)) != sizeof(num))
                {
                    fprintf(stderr, "Failed to write to child 1: %d %s\n",
                            errno, strerror(errno));
                    exit(EXIT_FAILURE);
                }
            }
            fflush(stdout);
        }
        if (num != -1)
            printf("Parent: exited loop on read failure\n");
        close(even[1]);
        close(odd[1]);

        /* Wait for child processes to exit */
        int corpse;
        int status;
        while ((corpse = wait(&status)) > 0)
            printf("PID %5d exited with status 0x%.4X\n", corpse, status);
    }

    return 0;
}

我使用随机数生成器生成一系列范围在 -1 到 100 之间的数字;它使用我选择的种子在条目 63 处生成 -1:

67 42 2 41 63 72 17 64 8 21 72 9 98 5 10 30 29 69 18 71 82
93 98 42 81 85 51 67 44 6 17 96 32 38 29 29 88 61 48 68 70 9
19 41 13 45 9 57 37 93 75 67 35 93 45 35 60 51 2 41 56 52 -1

我得到的运行之一(源代码:pipe67.c;程序:pipe67;数据文件:pipe67.in)是:

$ gcc -O3 -g -std=c11 -Wall -Wextra -Werror -Wmissing-prototypes -Wstrict-prototypes -fno-common pipe67.c -o pipe67
$ pipe67 < pipe67.in
Parent: even[R] = 5, even[W] = 6, odd[R] = 3, odd[W] = 4
Child 1: 52237
Child 2: 52238
Child 1 at work: 52237
Parent - to child 1: (1) 67
Parent - to child 2: (2) 42
Child 1: odd[R] = 3
Parent - to child 2: (3) 2
Parent - to child 1: (4) 41
Parent - to child 1: (5) 63
Parent - to child 2: (6) 72
Parent - to child 1: (7) 17
Parent - to child 2: (8) 64
Parent - to child 2: (9) 8
Parent - to child 1: (10) 21
Parent - to child 2: (11) 72
Parent - to child 1: (12) 9
Parent - to child 2: (13) 98
Parent - to child 1: (14) 5
Parent - to child 2: (15) 10
Parent - to child 2: (16) 30
Parent - to child 1: (17) 29
Parent - to child 1: (18) 69
Parent - to child 2: (19) 18
Parent - to child 1: (20) 71
Parent - to child 2: (21) 82
Parent - to child 1: (22) 93
Parent - to child 2: (23) 98
Parent - to child 2: (24) 42
Parent - to child 1: (25) 81
Parent - to child 1: (26) 85
Parent - to child 1: (27) 51
Parent - to child 1: (28) 67
Parent - to child 2: (29) 44
Parent - to child 2: (30) 6
Parent - to child 1: (31) 17
Parent - to child 2: (32) 96
Parent - to child 2: (33) 32
Parent - to child 2: (34) 38
Parent - to child 1: (35) 29
Parent - to child 1: (36) 29
Parent - to child 2: (37) 88
Parent - to child 1: (38) 61
Parent - to child 2: (39) 48
Parent - to child 2: (40) 68
Parent - to child 2: (41) 70
Parent - to child 1: (42) 9
Parent - to child 1: (43) 19
Parent - to child 1: (44) 41
Child 2 at work: 52238
Parent - to child 1: (45) 13
Parent - to child 1: (46) 45
Parent - to child 1: (47) 9
Parent - to child 1: (48) 57
Parent - to child 1: (49) 37
Parent - to child 1: (50) 93
Child 2: even[R] = 5
Parent - to child 1: (51) 75
Parent - to child 1: (52) 67
Parent - to child 1: (53) 35
Parent - to child 1: (54) 93
Parent - to child 1: (55) 45
Parent - to child 1: (56) 35
Parent - to child 2: (57) 60
Parent - to child 1: (58) 51
Parent - to child 2: (59) 2
Parent - to child 1: (60) 41
Parent - to child 2: (61) 56
Parent - to child 2: (62) 52
Thanks for your 63 numbers!
Child 1: (1) 67
Child 2: (1) 42
Child 2: (2) 2
Child 1: (2) 41
Child 2: (3) 72
Child 1: (3) 63
Child 2: (4) 64
Child 1: (4) 17
Child 2: (5) 8
Child 1: (5) 21
Child 2: (6) 72
Child 1: (6) 9
Child 2: (7) 98
Child 1: (7) 5
Child 2: (8) 10
Child 1: (8) 29
Child 2: (9) 30
Child 1: (9) 69
Child 2: (10) 18
Child 1: (10) 71
Child 2: (11) 82
Child 1: (11) 93
Child 2: (12) 98
Child 1: (12) 81
Child 2: (13) 42
Child 1: (13) 85
Child 2: (14) 44
Child 1: (14) 51
Child 2: (15) 6
Child 1: (15) 67
Child 2: (16) 96
Child 1: (16) 17
Child 2: (17) 32
Child 1: (17) 29
Child 2: (18) 38
Child 1: (18) 29
Child 2: (19) 88
Child 1: (19) 61
Child 2: (20) 48
Child 1: (20) 9
Child 2: (21) 68
Child 1: (21) 19
Child 2: (22) 70
Child 1: (22) 41
Child 2: (23) 60
Child 1: (23) 13
Child 2: (24) 2
Child 1: (24) 45
Child 2: (25) 56
Child 1: (25) 9
Child 2: (26) 52
Child 1: (26) 57
Child 2: end of loop (rc = 0)
Child 1: (27) 37
Child 1: (28) 93
Child 1: (29) 75
Child 1: (30) 67
Child 1: (31) 35
Child 1: (32) 93
Child 1: (33) 45
Child 1: (34) 35
Child 1: (35) 51
Child 1: (36) 41
Child 1: end of loop (rc = 0)
PID 52238 exited with status 0x0000
PID 52237 exited with status 0x0000
$

我还编写了一个“dumper”程序(源代码dump97.c编译为dump97 - 编译类似于pipe67 编译)验证两个输出文件:

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

int main(int argc, char **argv)
{
    if (argc != 2)
    {
        fprintf(stderr, "Usage: %s bin-file\n", argv[0]);
        exit(EXIT_FAILURE);
    }

    FILE *fp = fopen(argv[1], "rb");
    if (fp == NULL)
    {
        fprintf(stderr, "%s: failed to open file '%s' for reading\n", argv[0], argv[1]);
        exit(EXIT_FAILURE);
    }

    int counter = 0;
    int num;
    while (fread(&num, sizeof(num), 1, fp) == 1)
        printf("%d: %d\n", ++counter, num);

    fclose(fp);
    return 0;
}

运行这些文件给出:

$ dump97 odd.bin
1: 67
2: 41
3: 63
4: 17
5: 21
6: 9
7: 5
8: 29
9: 69
10: 71
11: 93
12: 81
13: 85
14: 51
15: 67
16: 17
17: 29
18: 29
19: 61
20: 9
21: 19
22: 41
23: 13
24: 45
25: 9
26: 57
27: 37
28: 93
29: 75
30: 67
31: 35
32: 93
33: 45
34: 35
35: 51
36: 41
$ dump97 even.bin
1: 42
2: 2
3: 72
4: 64
5: 8
6: 72
7: 98
8: 10
9: 30
10: 18
11: 82
12: 98
13: 42
14: 44
15: 6
16: 96
17: 32
18: 38
19: 88
20: 48
21: 68
22: 70
23: 60
24: 2
25: 56
26: 52
$

一切似乎都是一致的。

Here's the code I derived from yours. It works for me. I too got rid of hasData. The two child processes are largely symmetric — it took me a depressingly long time to spot the one piece of asymmetry I introduced. One 'major' change is to call the output files odd.bin and even.bin since they contain binary data, not text (so the names odd.txt and even.txt are singularly inappropriate). It would be easy and sensible to revise them to text files using standard I/O (fopen(), fprintf(), fclose()) to write the numbers. Another significant change is that it only prompts for "Enter a num:" if the input is a terminal — this is cleaner when driven from a pipe or data file.

There's a lot of diagnostic output — partly as I was trying to track down that annoying asymmetry that I mentioned (it was a case of == vs !=, as it happens). The signal handling in the parent is there also to help with the tracking.

/* SO 7130-7840 */
#include <errno.h>
#include <fcntl.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/wait.h>
#include <unistd.h>

int main(void)
{
    int odd[2];
    int even[2];

    if (pipe(odd) != 0 || pipe(even) != 0)
    {
        fprintf(stderr, "Failed to create pipes: %d %s\n", errno, strerror(errno));
        exit(EXIT_FAILURE);
    }
    pid_t p1;
    pid_t p2;


    printf("Parent: even[R] = %d, even[W] = %d, odd[R] = %d, odd[W] = %d\n",
           even[0], even[1], odd[0], odd[1]);

    if ((p1 = fork()) < 0)
    {
        fprintf(stderr, "Failed to fork 1: %d %s\n", errno, strerror(errno));
        exit(EXIT_FAILURE);
    }
    else if (p1 == 0)
    {
        /* Child 1 - odd numbers */
        printf("Child 1 at work: %5d\n", (int)getpid());
        close(even[0]);
        close(even[1]);
        close(odd[1]);
        printf("Child 1: odd[R] = %d\n", odd[0]);

        const char *filename = "odd.bin";
        int odd_fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC, 0644);
        if (odd_fd < 0)
        {
            fprintf(stderr, "Child 1: failed to open file %s: %d %s\n",
                    filename, errno, strerror(errno));
            exit(EXIT_FAILURE);
        }

        int counter = 0;
        int num1;
        int rc;
        while ((rc = read(odd[0], &num1, sizeof(num1))) == sizeof(num1))
        {
            counter++;
            if (num1 % 2 != 0)
            {
                printf("Child 1: (%d) %d\n", counter, num1);
                write(odd_fd, &num1, sizeof(num1));
            }
            else
            {
                fprintf(stderr, "Child 1: got even number %d\n", num1);
                exit(EXIT_FAILURE);
            }
        }
        if (rc < 0)
            printf("Child 1: read error (rc = %d; %d: %s)\n", rc, errno, strerror(errno));
        else
            printf("Child 1: end of loop (rc = %d)\n", rc);

        close(odd_fd);
        close(odd[0]);
        exit(EXIT_SUCCESS);
    }
    else if ((p2 = fork()) < 0)
    {
        fprintf(stderr, "Failed to fork 2: %d %s\n", errno, strerror(errno));
        exit(EXIT_FAILURE);
    }
    else if (p2 == 0)
    {
        /* Child 2 - even numbers */
        printf("Child 2 at work: %5d\n", (int)getpid());
        close(odd[0]);
        close(odd[1]);
        close(even[1]);
        printf("Child 2: even[R] = %d\n", even[0]);

        const char *filename = "even.bin";
        int even_fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC, 0644);
        if (even_fd < 0)
        {
            fprintf(stderr, "Child 2: failed to open file %s: %d %s\n",
                    filename, errno, strerror(errno));
            exit(EXIT_FAILURE);
        }

        int counter = 0;
        int num2;
        int rc;
        while ((rc = read(even[0], &num2, sizeof(num2))) == sizeof(num2))
        {
            counter++;
            if (num2 % 2 == 0)
            {
                printf("Child 2: (%d) %d\n", counter, num2);
                write(even_fd, &num2, sizeof(num2));
            }
            else
            {
                fprintf(stderr, "Child 2: got odd number %d\n", num2);
                exit(EXIT_FAILURE);
            }
        }
        if (rc < 0)
            printf("Child 2: read error (rc = %d; %d: %s)\n", rc, errno, strerror(errno));
        else
            printf("Child 2: end of loop (rc = %d)\n", rc);

        close(even_fd);
        close(even[0]);
        exit(EXIT_SUCCESS);
    }
    else
    {
        /* Parent - read and distribute */
        printf("Child 1: %5d\n", p1);
        printf("Child 2: %5d\n", p2);

        signal(SIGPIPE, SIG_IGN);   /* Writing to broken pipe gives write error */

        close(odd[0]);
        close(even[0]);

        int counter = 0;
        int num;
        while ((!isatty(STDIN_FILENO) || printf("Enter a num: ") > 0) &&
               scanf("%d", &num) == 1)
        {
            counter++;
            if (num == -1)
            {
                printf("Thanks for your %d numbers!\n", counter);
                break;
            }
            else if (num % 2 == 0)
            {
                printf("Parent - to child 2: (%d) %d\n", counter, num);
                if (write(even[1], &num, sizeof(num)) != sizeof(num))
                {
                    fprintf(stderr, "Failed to write to child 2: %d %s\n",
                            errno, strerror(errno));
                    exit(EXIT_FAILURE);
                }
            }
            else
            {
                printf("Parent - to child 1: (%d) %d\n", counter, num);
                if (write(odd[1], &num, sizeof(num)) != sizeof(num))
                {
                    fprintf(stderr, "Failed to write to child 1: %d %s\n",
                            errno, strerror(errno));
                    exit(EXIT_FAILURE);
                }
            }
            fflush(stdout);
        }
        if (num != -1)
            printf("Parent: exited loop on read failure\n");
        close(even[1]);
        close(odd[1]);

        /* Wait for child processes to exit */
        int corpse;
        int status;
        while ((corpse = wait(&status)) > 0)
            printf("PID %5d exited with status 0x%.4X\n", corpse, status);
    }

    return 0;
}

I used a random number generator to generate a series of numbers in the range -1 to 100; it generated -1 at entry 63 with the seed I chose:

67 42 2 41 63 72 17 64 8 21 72 9 98 5 10 30 29 69 18 71 82
93 98 42 81 85 51 67 44 6 17 96 32 38 29 29 88 61 48 68 70 9
19 41 13 45 9 57 37 93 75 67 35 93 45 35 60 51 2 41 56 52 -1

One of the runs I got (source code: pipe67.c; program: pipe67; data file: pipe67.in) was:

$ gcc -O3 -g -std=c11 -Wall -Wextra -Werror -Wmissing-prototypes -Wstrict-prototypes -fno-common pipe67.c -o pipe67
$ pipe67 < pipe67.in
Parent: even[R] = 5, even[W] = 6, odd[R] = 3, odd[W] = 4
Child 1: 52237
Child 2: 52238
Child 1 at work: 52237
Parent - to child 1: (1) 67
Parent - to child 2: (2) 42
Child 1: odd[R] = 3
Parent - to child 2: (3) 2
Parent - to child 1: (4) 41
Parent - to child 1: (5) 63
Parent - to child 2: (6) 72
Parent - to child 1: (7) 17
Parent - to child 2: (8) 64
Parent - to child 2: (9) 8
Parent - to child 1: (10) 21
Parent - to child 2: (11) 72
Parent - to child 1: (12) 9
Parent - to child 2: (13) 98
Parent - to child 1: (14) 5
Parent - to child 2: (15) 10
Parent - to child 2: (16) 30
Parent - to child 1: (17) 29
Parent - to child 1: (18) 69
Parent - to child 2: (19) 18
Parent - to child 1: (20) 71
Parent - to child 2: (21) 82
Parent - to child 1: (22) 93
Parent - to child 2: (23) 98
Parent - to child 2: (24) 42
Parent - to child 1: (25) 81
Parent - to child 1: (26) 85
Parent - to child 1: (27) 51
Parent - to child 1: (28) 67
Parent - to child 2: (29) 44
Parent - to child 2: (30) 6
Parent - to child 1: (31) 17
Parent - to child 2: (32) 96
Parent - to child 2: (33) 32
Parent - to child 2: (34) 38
Parent - to child 1: (35) 29
Parent - to child 1: (36) 29
Parent - to child 2: (37) 88
Parent - to child 1: (38) 61
Parent - to child 2: (39) 48
Parent - to child 2: (40) 68
Parent - to child 2: (41) 70
Parent - to child 1: (42) 9
Parent - to child 1: (43) 19
Parent - to child 1: (44) 41
Child 2 at work: 52238
Parent - to child 1: (45) 13
Parent - to child 1: (46) 45
Parent - to child 1: (47) 9
Parent - to child 1: (48) 57
Parent - to child 1: (49) 37
Parent - to child 1: (50) 93
Child 2: even[R] = 5
Parent - to child 1: (51) 75
Parent - to child 1: (52) 67
Parent - to child 1: (53) 35
Parent - to child 1: (54) 93
Parent - to child 1: (55) 45
Parent - to child 1: (56) 35
Parent - to child 2: (57) 60
Parent - to child 1: (58) 51
Parent - to child 2: (59) 2
Parent - to child 1: (60) 41
Parent - to child 2: (61) 56
Parent - to child 2: (62) 52
Thanks for your 63 numbers!
Child 1: (1) 67
Child 2: (1) 42
Child 2: (2) 2
Child 1: (2) 41
Child 2: (3) 72
Child 1: (3) 63
Child 2: (4) 64
Child 1: (4) 17
Child 2: (5) 8
Child 1: (5) 21
Child 2: (6) 72
Child 1: (6) 9
Child 2: (7) 98
Child 1: (7) 5
Child 2: (8) 10
Child 1: (8) 29
Child 2: (9) 30
Child 1: (9) 69
Child 2: (10) 18
Child 1: (10) 71
Child 2: (11) 82
Child 1: (11) 93
Child 2: (12) 98
Child 1: (12) 81
Child 2: (13) 42
Child 1: (13) 85
Child 2: (14) 44
Child 1: (14) 51
Child 2: (15) 6
Child 1: (15) 67
Child 2: (16) 96
Child 1: (16) 17
Child 2: (17) 32
Child 1: (17) 29
Child 2: (18) 38
Child 1: (18) 29
Child 2: (19) 88
Child 1: (19) 61
Child 2: (20) 48
Child 1: (20) 9
Child 2: (21) 68
Child 1: (21) 19
Child 2: (22) 70
Child 1: (22) 41
Child 2: (23) 60
Child 1: (23) 13
Child 2: (24) 2
Child 1: (24) 45
Child 2: (25) 56
Child 1: (25) 9
Child 2: (26) 52
Child 1: (26) 57
Child 2: end of loop (rc = 0)
Child 1: (27) 37
Child 1: (28) 93
Child 1: (29) 75
Child 1: (30) 67
Child 1: (31) 35
Child 1: (32) 93
Child 1: (33) 45
Child 1: (34) 35
Child 1: (35) 51
Child 1: (36) 41
Child 1: end of loop (rc = 0)
PID 52238 exited with status 0x0000
PID 52237 exited with status 0x0000
$

I also wrote a 'dumper' program (source dump97.c compiled to dump97 — compilation analogous to the pipe67 compilation) to validate the two output files:

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

int main(int argc, char **argv)
{
    if (argc != 2)
    {
        fprintf(stderr, "Usage: %s bin-file\n", argv[0]);
        exit(EXIT_FAILURE);
    }

    FILE *fp = fopen(argv[1], "rb");
    if (fp == NULL)
    {
        fprintf(stderr, "%s: failed to open file '%s' for reading\n", argv[0], argv[1]);
        exit(EXIT_FAILURE);
    }

    int counter = 0;
    int num;
    while (fread(&num, sizeof(num), 1, fp) == 1)
        printf("%d: %d\n", ++counter, num);

    fclose(fp);
    return 0;
}

Running those gave:

$ dump97 odd.bin
1: 67
2: 41
3: 63
4: 17
5: 21
6: 9
7: 5
8: 29
9: 69
10: 71
11: 93
12: 81
13: 85
14: 51
15: 67
16: 17
17: 29
18: 29
19: 61
20: 9
21: 19
22: 41
23: 13
24: 45
25: 9
26: 57
27: 37
28: 93
29: 75
30: 67
31: 35
32: 93
33: 45
34: 35
35: 51
36: 41
$ dump97 even.bin
1: 42
2: 2
3: 72
4: 64
5: 8
6: 72
7: 98
8: 10
9: 30
10: 18
11: 82
12: 98
13: 42
14: 44
15: 6
16: 96
17: 32
18: 38
19: 88
20: 48
21: 68
22: 70
23: 60
24: 2
25: 56
26: 52
$

That all seems consistent.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文