【问题标题】:fflush doesn't work in named pipefflush 在命名管道中不起作用
【发布时间】:2012-12-08 09:54:44
【问题描述】:

我有这个代码: 当第一个孩子向第二个孩子发送数据时,程序卡住了, 第二个孩子做 fscanf 然后卡住了,因为他看不懂我找不到原因。 请帮助我了解如何确保 fflush 将传输数据。

int main()
{
    pid_t childPid ; //Child's and father process id.
    int i ; //An index to create children in loop.
    unsigned int st_search_prime = 0 ;

    if((mkfifo(FIRST_FIFO, S_IFIFO | 0644) == FAIL && errno != EEXIST) ||
       (mkfifo(SECOND_FIFO, S_IFIFO | 0644) == FAIL && errno != EEXIST))
    {
        perror("Cannot create fifo file") ;
        exit(EXIT_FAILURE) ;
    }
    //create the children
    for(i = 0 ; i < NUM_OF_CHILDS  ; i++)
    {
        childPid = fork() ;
        if(childPid < 0)    //Fork failed.
        {
            perror("Cannot fork()") ;
            exit(EXIT_FAILURE) ;
        }
        else if(childPid == CHILD)  //child process
        {
            if(i == FIRST_SON)  //the 1st child process
                doChild1(st_search_prime) ;
            else        //the 2nd child process.
                doChild2(st_search_prime) ;
        }
    }
    //wait for the children to exit.
    for(i = 0 ; i < NUM_OF_CHILDS ; i++)
        wait(&childPid) ;

    return(EXIT_SUCCESS) ;
}

void doChild1(unsigned int st_search_prime)
{
    int counter = 0 ; //Counter for N successfully raffle .
    FILE* fdw1 ;
    FILE* fdr2 ;

    if((!(fdw1 = fopen(FIRST_FIFO, "w"))))
    {
        perror("Cannot open fifo file for w/r") ;
        exit(EXIT_FAILURE) ;
    }

    if((!(fdr2 = fopen(SECOND_FIFO, "r"))))
    {
        perror("Cannot open fifo file for w/r") ;
        exit(EXIT_FAILURE) ;
    }

    for(; counter < N ; counter++)
    {
        st_search_prime = raffle_prime(st_search_prime) ;
        **fprintf(fdw1, "%u\n", st_search_prime) ;
        fflush(fdw1) ;**
        printf("%u\n", st_search_prime) ;
        fscanf(fdr2, "%u\n", &st_search_prime) ;
    }
    fclose(fdw1) ;
    fclose(fdr2) ;

    exit(EXIT_SUCCESS) ;
}

void doChild2(unsigned int st_search_prime)
{
    int counter = 0 ; //Counter for N successfully raffle .
    FILE* fdw2 ;
    FILE* fdr1 ;

    if((!(fdr1 = fopen(FIRST_FIFO, "r"))))
    {
        perror("Cannot open fifo file for w/r") ;
        exit(EXIT_FAILURE) ;
    }
    if(!(fdw2 = fopen(SECOND_FIFO, "w")))
    {
        perror("Cannot open fifo file for w/r") ;
        exit(EXIT_FAILURE) ;
    }

    for(; counter < N ; counter++)
    {
        **fscanf(fdr1, "%u\n", &st_search_prime);**
        st_search_prime = raffle_prime(st_search_prime) ;
        fprintf(fdw2, "%u\n", st_search_prime) ;
        fflush(fdw2) ;
        printf("%u\n", st_search_prime) ;
    }
    fclose(fdr1) ;
    fclose(fdw2) ;

    exit(EXIT_SUCCESS) ;
}

【问题讨论】:

  • 考虑为固定字节数调用 read(),然后对 read 返回的字符串调用 sscanf。在管道上读取也将返回更少的字节 - fscanf 被阻塞,因为文件指针不在您假设的位置。 read() 不“关心”,只会返回那里的内容。
  • 事实上,您的问题可能与缺少的代码片段有关。请提供MCVE

标签: c


【解决方案1】:

尝试添加呼叫setlinebuf(fdw1) - 这应该会有所帮助。

此调用强制在换行后刷新缓冲区。您也可以使用setvbuf() 和参数_IOLBF 来获得相同的效果,或者使用_IONBF 来完全禁用缓冲。

【讨论】:

  • tnx,但程序仍然卡住。
【解决方案2】:

我认为问题在于 \n 在您的 fscanf 模式中的使用。 fscanf 的手册页说:

格式字符串由一系列指令组成 描述如何处理输入字符的序列。如果 指令的处理失败,没有进一步的输入被读取,并且 scanf() 返回。 “失败”可能是以下任何一种情况: 输入失败,意味着输入字符不可用,或 匹配失败,意味着输入不合适......

此外,根据指令我们有:

一系列空白字符(空格、制表符、换行符等;参见 空间(3))。该指令匹配任意数量的空白, 在输入中不包括任何内容。

所以,当您在doChild2 中使用fscanf 模式"%u\n" 时,该模式由两个输入指令组成,%u 匹配传入的数字,然后\n 匹配传入的换行符(白色空间)。此时fscanf 将继续寻找更多的输入,因为没有更多的输入被发送导致您的程序阻塞。

为什么fscanf 回去寻找更多输入?上面的第一个引用告诉我们终止的两个条件,要么没有更多的输入;要么那么先进先出仍然打开,所以我们不知道没有更多的输入,所以条件不满足,或者,如果指令匹配失败,fscanf 将返回;但这还没有发生。

就修复而言,从fscanf 模式中删除\n 就足够了。手册页告诉我们:

大多数转换会丢弃初始空白字符...

%u 就是这种情况,因此如果您使用%u\n 的模式发送但fscanf 使用%u 的模式,那么\n 将导致@ 上的匹配失败987654339@ 指令,导致fscanf 返回。这会将\n 留在输入缓冲区中,但是,下一次对fscanf 的调用将丢弃初始空白(换行符),一切都会好起来的。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多