【问题标题】:Pipe in C — read and write in my programC 中的管道——在我的程序中读写
【发布时间】:2018-06-11 17:10:39
【问题描述】:

我希望我的程序显示如下结果:

child: 2 4 6 8 10  
parent: 3 6 9 12 15  
child 12 14 16 18 20  
parent 18 21 24 27 30  

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

main(int argc,char *argv[]){
int i=0,tube1[2],tube2[2],pid,tube3[2];
if(pipe(tube1)||pipe(tube2)==-1){
perror("pipe");
exit(0);
}
pid=fork();

while(i<100){

if(pid==0){
printf("fils ");

do{
i=i+2;
printf("%d ",i);
}while(i%5!=0);


write(tube1[1],&i,sizeof(int));

read(tube2[0],&i,sizeof(int));


}

else{



printf("pere ");
read(tube1[0],&i,sizeof(int));
do{

i=i+3;
printf("%d ",i);
}while(i%5!=0);


write(tube2[1],&i,sizeof(int));



}

printf("\n");








}
close(tube1[1]);
close(tube1[0]);
close(tube2[1]);
close(tube2[0]);
}

但是我的程序有问题;我不明白为什么。

【问题讨论】:

  • 这条线并没有像你想象的那样做:if(pipe(tube1)||pipe(tube2)==-1){
  • @slugonamission:这条线是自不一致的,这很糟糕,但它确实有效,因为pipe() 在失败时返回非零值(-1),在成功时返回零,所以如果第一个 pipe() 失败,第一个测试触发 if 语句的主体,就像第二个 pipe() 失败时第二个测试触发主体一样。
  • 重新缩进您的代码,在运算符周围放置适当的空格以使其可读
  • 编译所有警告和调试信息:gcc -Wall -Wextra -gGCC。然后use the gdb debugger

标签: c pipe


【解决方案1】:

清理后,您的代码如下所示:

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

int main(void)
{
    int i = 0, tube1[2], tube2[2], pid;
    if (pipe(tube1) == -1 || pipe(tube2) == -1)
    {
        perror("pipe");
        exit(0);
    }
    pid = fork();

    while (i < 100)
    {
        if (pid == 0)
        {
            printf("fils ");
            do
            {
                i = i + 2;
                printf("%d ", i);
            } while (i % 5 != 0);
            putchar('\n');

            write(tube1[1], &i, sizeof(int));
            read(tube2[0], &i, sizeof(int));
        }
        else
        {
            printf("pere ");
            read(tube1[0], &i, sizeof(int));
            do
            {
                i = i + 3;
                printf("%d ", i);
            } while (i % 5 != 0);
            putchar('\n');

            write(tube2[1], &i, sizeof(int));
        }
    }
    close(tube1[1]);
    close(tube1[0]);
    close(tube2[1]);
    close(tube2[0]);
}

一个变化是进程在写入一系列数字后输出换行符,而不是等到读/写操作之后。

循环是复杂的,因为您有一个外部while (i &lt; 100) 循环,然后每个进程都有一个递增i 的内部循环。然后,更复杂的事情是,孩子将其当前值i 发送给父母,父母在其循环中使用它,然后父母将自己的i 值发送给孩子,孩子恢复它的使用i 的新值;冲洗并重复。输出是:

fils 2 4 6 8 10 
pere 13 16 19 22 25 
fils 27 29 31 33 35 
pere 38 41 44 47 50 
fils 52 54 56 58 60 
pere 63 66 69 72 75 
fils 77 79 81 83 85 
pere 88 91 94 97 100 

可以看到孩子生成的值是10;然后父母将 3 添加到它从孩子收到的值(因此为 13)并迭代;然后它将 25 发送给孩子,孩子加 2(因此为 27)并迭代;等等。

要获得您寻求的结果,您需要将同步中使用的值与控制循环的值分离。您还面临一个问题,因为子进程会尝试比父进程运行更长的时间,但幸运的是,它会收到一个 SIGPIPE 信号,并且当它尝试写入父进程已关闭的管道时会死掉——或者更确切地说,如果它已经关闭了它不使用的管道末端。在生成换行符之后刷新标准输出也是一个好主意。这些变化导致:

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

int main(void)
{
    int i = 0, tube1[2], tube2[2], pid;
    if (pipe(tube1) == -1 || pipe(tube2) == -1)
    {
        perror("pipe");
        exit(1);
    }
    pid = fork();
    if (pid < 0)
    {
        perror("fork");
        exit(1);
    }
    if (pid == 0)
    {
        close(tube1[0]);
        close(tube2[1]);
    }
    else
    {
        close(tube1[1]);
        close(tube2[0]);
    }

    while (i < 100)
    {
        if (pid == 0)
        {
            printf("fils ");
            do
            {
                i = i + 2;
                printf("%d ", i);
            } while (i % 5 != 0);
            putchar('\n');
            fflush(stdout);

            int j = 0;
            write(tube1[1], &j, sizeof(int));
            read(tube2[0], &j, sizeof(int));
        }
        else
        {
            int j = 0;
            read(tube1[0], &j, sizeof(int));

            printf("pere ");
            do
            {
                i = i + 3;
                printf("%d ", i);
            } while (i % 5 != 0);
            putchar('\n');
            fflush(stdout);

            write(tube2[1], &j, sizeof(int));
        }
    }
    close(tube1[1]);
    close(tube1[0]);
    close(tube2[1]);
    close(tube2[0]);
}

然后输出是:

fils 2 4 6 8 10 
pere 3 6 9 12 15 
fils 12 14 16 18 20 
pere 18 21 24 27 30 
fils 22 24 26 28 30 
pere 33 36 39 42 45 
fils 32 34 36 38 40 
pere 48 51 54 57 60 
fils 42 44 46 48 50 
pere 63 66 69 72 75 
fils 52 54 56 58 60 
pere 78 81 84 87 90 
fils 62 64 66 68 70 
pere 93 96 99 102 105 
fils 72 74 76 78 80 

请注意,孩子没有达到 100,因为父母退出,而父母超过 100,因为检查发生在外循环,而不是内循环。

我保留了你的循环组织,但如果它是我自己的代码,它将有两个函数——be_childish()be_parental()——它们将在 fork 之后调用,并且每个函数都将运行自己的相关循环。管道将被传递给函数,它们会“更好地”清理。请注意,程序末尾的 4 个 close() 调用中有 2 个将失败,因为这些管道描述符之前已关闭。区分哪些是繁琐的;最好把代码拆分成函数。

【讨论】:

    猜你喜欢
    • 2013-01-29
    • 1970-01-01
    • 2014-03-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多