c++ 从管道阅读数据时出现异常行为

sq1bmfud  于 2023-01-18  发布在  其他
关注(0)|答案(1)|浏览(95)

在我仔细阅读了手册(即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

到目前为止看起来还可以,令人困惑的是,当我增加要读取的字节数时,输出非常奇怪,下面是所说的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返回的文件描述符使用哪种类型的缓冲区。而且我在手册上找不到任何有用的信息(即man 2 pipe)。
有人能解释一下这件事吗?

a64a0gku

a64a0gku1#

>具有比=高的operator precedence。因此,

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

相当于

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

第一次迭代似乎消耗了所有数据,因此read应该返回1212 > 0true,并且true隐式转换为整数值1
下一次迭代read应该返回一个非正数,从而结束循环。
read大小为1时,其预期返回值与1 > 0的结果无法区分。
在作业两边加上括号。

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

相关问题