从管道读取数据时的奇怪行为

Strange behavior when reading data from pipe

仔细阅读手册后(即man 2 pipe),我找到了一个演示代码片段:

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

       int
       main(int argc, char *argv[])
       {
           int pipefd[2];
           pid_t cpid;
           char buf;

           if (argc != 2) {
            fprintf(stderr, "Usage: %s <string>\n", argv[0]);
            exit(EXIT_FAILURE);
           }

           if (pipe(pipefd) == -1) {
               perror("pipe");
               exit(EXIT_FAILURE);
           }

           cpid = fork();
           if (cpid == -1) {
               perror("fork");
               exit(EXIT_FAILURE);
           }

           if (cpid == 0) {    /* Child reads from pipe */
               close(pipefd[1]);          /* Close unused write end */

               while (read(pipefd[0], &buf, 1) > 0)
                   write(STDOUT_FILENO, &buf, 1);

               write(STDOUT_FILENO, "\n", 1);
               close(pipefd[0]);
               _exit(EXIT_SUCCESS);

           } else {            /* Parent writes argv[1] to pipe */
               close(pipefd[0]);          /* Close unused read end */
               write(pipefd[1], argv[1], strlen(argv[1]));
               close(pipefd[1]);          /* Reader will see EOF */
               wait(NULL);                /* Wait for child */
               exit(EXIT_SUCCESS);
           }
       }

我对上面的代码片段做了一些小修改(即:在父进程中添加 sleep 并在子进程中打印出 read 返回的大小)。

#include <sys/wait.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <string>
#include <thread>
#include <array>
#include <iostream>

int
main(int argc, char *argv[])
{
    int pipefd[2];
    pid_t cpid;
    std::array<char, 1024> buf;
    
    if (pipe(pipefd) == -1) {
        perror("pipe");
        exit(EXIT_FAILURE);
    }
    cpid = fork();
    if (cpid == -1) {
        perror("fork");
        exit(EXIT_FAILURE);
    }
    if (cpid == 0) {    /* Child reads from pipe */
        close(pipefd[1]);          /* Close unused write end */
        int size;
        while (size = read(pipefd[0], buf.data(), 1) > 0)
             std::cout << size << std::endl;
        write(STDOUT_FILENO, "\n", 1);
        close(pipefd[0]);
        _exit(EXIT_SUCCESS);
    } else {            /* Parent writes argv[1] to pipe */
        close(pipefd[0]);          /* Close unused read end */
        std::string str{"hello world\n"};
        write(pipefd[1], str.c_str(), str.size());
        std::this_thread::sleep_for(std::chrono::seconds(5));
        close(pipefd[1]);          /* Reader will see EOF */
        wait(NULL);                /* Wait for child */
        exit(EXIT_SUCCESS);
    }
}

以上代码片段的输出如下:

1
1
1
1
1
1
1
1
1
1
1
1

目前看来还不错。令人困惑的是,当我将字节数增加到 read.The 时,输出非常 strange.Here 就是所说的 code snippet:

#include <sys/wait.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <string>
#include <thread>
#include <array>
#include <iostream>

int
main(int argc, char *argv[])
{
    int pipefd[2];
    pid_t cpid;
    std::array<char, 1024> buf;
    
    if (pipe(pipefd) == -1) {
        perror("pipe");
        exit(EXIT_FAILURE);
    }
    cpid = fork();
    if (cpid == -1) {
        perror("fork");
        exit(EXIT_FAILURE);
    }
    if (cpid == 0) {    /* Child reads from pipe */
        close(pipefd[1]);          /* Close unused write end */
        int size;
        while (size = read(pipefd[0], buf.data(), buf.size()) > 0)
             std::cout << size << std::endl;
        write(STDOUT_FILENO, "\n", 1);
        close(pipefd[0]);
        _exit(EXIT_SUCCESS);
    } else {            /* Parent writes argv[1] to pipe */
        close(pipefd[0]);          /* Close unused read end */
        std::string str{"hello world\n"};
        write(pipefd[1], str.c_str(), str.size());
        std::this_thread::sleep_for(std::chrono::seconds(5));
        close(pipefd[1]);          /* Reader will see EOF */
        wait(NULL);                /* Wait for child */
        exit(EXIT_SUCCESS);
    }
}

这是奇怪的输出:

1
//new line, and no more output indeed.

也许我需要知道 pipe use.And 返回的文件描述符的缓冲类型我在手册中找不到任何有用的信息(即 man 2 pipe)。

有人能解释一下这件事吗?

>operator precedence 高于 =。因此,

size = read(pipefd[0], buf.data(), buf.size()) > 0

等同于

size = (read(pipefd[0], buf.data(), buf.size()) > 0)

第一次迭代似乎会消耗所有数据,因此 read 应该 return 1212 > 0truetrue 隐式转换为整数值 1

下一次迭代,read应该return一个non-positive数字,结束循环。

read 大小为 1 时,其预期 return 值与 1 > 0.

的结果没有区别

在赋值前后加上括号。

(size = read(pipefd[0], buf.data(), buf.size())) > 0