当两个管道属于同一个过程时,如何冲洗管道来清理C中的缓冲区?

时间:2014-05-22 04:23:54

标签: c linux pipe flush

在X函数中,我使用管道来缓冲(一对printfs,它们在X函数内部调用的Y函数中打印)stdout流(如果有一个Fd,然后是缓冲区)完成后,关闭一个管道和其他Fd,然后在其上使用printf

我想完全确定缓冲区是空的,下次再次调用此X函数来执行任务时。 我尝试了一些我在网上找到的东西:

  1. fflush
  2. ioctl_flushlbf:看起来他们没有得到gcc的支持。 g ++是否支持它?
  3. fseek(stdin,EOF,SEEK_END);
  4. fpurge(ofp);
  5. 我多次调用X()函数。我写的现在的代码,如果下一组输出大于先前的设置,则工作正常。

    如果下一组输出小于当前输出组。然后下一组有一些额外的垃圾值,这给了我一个指示,缓冲区可能没有完全刷新。

    由于某些原因,我用C编写了整个代码但是使用了g ++编译器。

    我的代码如下:

    void X(int pairs,char* expOut)
    {
        char buf[256];
        int fds[2];
        char output[300];
        char input[50];
    
        /* opening pipes */
        pipe(fds);
    
        /* saving the the given stdout stream */
        int bak = dup(STDOUT_FILENO);
    
        /* associating Fds[1] pipe with stdout */
        int res=dup2(fds[1],STDOUT_FILENO);
    
        /* associating Fds[0] pipe with stdin */
        dup2(fds[0],STDIN_FILENO);
        assert(res!=-1);
    
        /* Call To function Y: function combParenthesis is a recursive function,
         which prints out some strings couple of time */
        combParenthesis(pairs) ;
    
        fflush(stdout);
    
        /* closing stdout FD stream */
        close(fds[1]);
        fflush(stdout);
    
        /* restoring the old stdout stream */
        dup2(bak, 1);
        close(bak);
    
        /* opening, stdin stream for reading */
        FILE *ofp = fdopen(fds[0], "r");
    
        char strs[30][30];
        for (int i=0;i<30;i++) {
            memset(strs[i], 0, 30);
    
        }
    
        int i=0;
        if (ofp)
        {
            int sz;
            if((pairs*2)+1 <= 1)
            {
                sz=5;
            }
            else
            {sz = (pairs*2)+1 ;}
    
            /* read the stream  line by line */
            while (fgets(buf,sz ,ofp)) {
                printf("\n next string %s", buf);
    
                i++;
            }
    
            if (ferror(ofp)) {
                printf("something went wrong in the input to printf");
    
            }
    
        }
    
        /* different ways to flush it out  */
        char c;
        while( (c = fgetc( ofp )) != EOF && c != '\n' );
        fseek(stdin,EOF,SEEK_END);
        fpurge(ofp);
        fclose(ofp);
        fflush(stdin);
        // _flushlbf();
    
        /* close the  fd associated with stdin */
        close(fds[0]);    
    }
    

1 个答案:

答案 0 :(得分:1)

编辑:fflush定位结束时的精度。

我设法使用我自己的combParenthesis来运行你的代码(第一遍:中等字符串,第二遍:大字符串,第三小字符串)。我从未在输出中发现垃圾......只要我将printf("\n next string %s", buf);替换为stderr上的输出

       fprintf(stderr, "\n next string %s", buf);

通过在stdin和ofp之后用一个fflush(stdout)刷新标准输出,我也得到了正确的输出。恕我直言,问题是:

  • 关闭管道,因此stdout不再复制到ofp或stdin
  • 您使用printf("\n next string %s", buf) 在stdout上写文,并且可以缓冲标准草
  • 刷新已经干净的流
  • 当你在下次通话中复制stdout时,你可能会读到stdout中最后一次传递的内容

以下是我发现的主要改进:

  • 如果您的combParenthesis读取输出带有管道重复标准输出,则永远不要在任何地方写入stdout(或确保将其刷新)
  • 你做了一个不必要的dup2(fds[0],STDIN_FILENO);,因为你直接阅读了管道的另一端(这是更好的)
  • 您永远不会确认sz = (pairs*2)+1小于sizeof(buf)

编辑:事实上,我刚刚意识到你的代码可以工作,即使你在应用程序的其他地方混合了printf,只要你在之前刷新stdout 将它复制到fds [1]

所以这里是X()功能的固定版本,带有明确的编辑功能(但恕我直言,你应该考虑我的其他建议):

void X(int pairs,char* expOut)
{
    char buf[256];
    int fds[2];
    char output[300];
    char input[50];

    /* BEGIN EDIT */
    /* first flush stdout */
    fflush(stdout);
    /* END EDIT */

    /* opening pipes */
    pipe(fds);

    /* saving the the given stdout stream */
    int bak = dup(STDOUT_FILENO);

    /* associating Fds[1] pipe with stdout */
    int res=dup2(fds[1],STDOUT_FILENO);

    /* associating Fds[0] pipe with stdin */
    dup2(fds[0],STDIN_FILENO);
    assert(res!=-1);

    /* Call To function Y: function combParenthesis is a recursive function,
     which prints out some strings couple of time */
    combParenthesis(pairs) ;


    /* closing stdout FD stream */
    close(fds[1]);
    fflush(stdout);

    /* restoring the old stdout stream */
    dup2(bak, 1);
    close(bak);

    /* opening, stdin stream for reading */
    FILE *ofp = fdopen(fds[0], "r");

    char strs[30][30];
    for (int i=0;i<30;i++) {
        memset(strs[i], 0, 30);

    }

    int i=0;
    if (ofp)
    {
        int sz;
        if((pairs*2)+1 <= 1)
        {
            sz=5;
        }
        else
        {sz = (pairs*2)+1 ;}

        /* read the stream  line by line */
    // EDIT : changed sz with sizeof(buf)-1 - cause: no correct pairs value
        while (fgets(buf, sizeof(buf) - 1,ofp)) {
            printf("\n next string %s", buf);

            i++;
        }

        if (ferror(ofp)) {
            printf("something went wrong in the input to printf");

        }

    }

    /* different ways to flush it out  */
    /* BEGIN EDIT : ALL FLUSHING COMMENTED OUT 
    char c;
    while( (c = fgetc( ofp )) != EOF && c != '\n' );
    fseek(stdin,EOF,SEEK_END);
    fpurge(ofp);
    fclose(ofp);
    fflush(stdin);
    // _flushlbf();
    END EDIT */

    /* close the  fd associated with stdin */
    close(fds[0]);    
}

我从未在读取内容中获得垃圾,即使将输出重定向到文件也能正常工作,但由于我无法解释的原因,消息的顺序并不是我所期望的。希望你不关心