【问题标题】:read() not blocking as expectedread() 没有按预期阻塞
【发布时间】:2020-11-21 18:38:38
【问题描述】:

我在 C++ 程序中有一个线程,专门用于读取通过等待用户输入的 bash 脚本写入的命名管道。我希望 ReadFromPipe() 每次通过管道发送时都会阻塞并对用户输入做出反应。

read() 在这段代码 sn-p 中没有阻止我,我不确定为什么。

重击:

# create pipe
write_pipe=/tmp/bash_to_c

if [[ ! -p $write_pipe ]]; then
    mkfifo $write_pipe
fi

USER_INPUT=""

while true; do
    read USER_INPUT
    echo $USER_INPUT > $write_pipe
done

C++:

std::string ReadFromPipe()
{
    char buffer[500];
    int fd; 
    std::string pipe = "./tmp/bash_to_c";

    fd = open(pipe.c_str(), O_RDONLY);
    read(fd, buffer, 500);
    
    buffer[strcspn(buffer, "\n")] = 0;
    buffer[strlen(buffer)] = '\0';
    
    close(fd);

    return std::string(buffer);
}

void* pipeCommunicationThreadFunc(void *args)
    {
        bool continueReadingFromPipe = true;
        while(continueReadingFromPipe)
        {
            // read from pipe
            std::string message = ReadFromPipe();
            std::cout << "message: " << message << std::endl;
        }
    }

【问题讨论】:

  • 打印什么吗?
  • “不阻塞”是指它从不等待并返回一个空字符串吗?还是等待然后返回部分字符串?
  • 您没有检查打开管道是否真的成功 - 文件名 "./tmp/bash_to_c" 看起来不对。您创建的是"/tmp/bash_to_c" 而不是"./tmp/bash_to_c",所以除非您从/ 启动程序,否则它失败。执行cd /,然后键入 C++ 程序的路径以运行它。那它就可以工作了。
  • 如果它读取的字符串没有换行符,就会发生各种不好的事情......你需要使用read()的返回值而不是忽略它。使用std::ifstream 更容易读取它,因此您不必实现自己的基于行的缓冲。
  • buffer[strlen(buffer)] = '\0'; 是一种反模式。 strlen 搜索预先存在的 NUL 终止符,因此如果没有,则此语句不会添加一个,但会导致未定义的行为。去掉这条线,没有意义。确保以其他方式存在 NUL。更好的是,如果可能,切换到 C++ 字符串。

标签: c++ bash pipe


【解决方案1】:

您没有检查打开管道是否真的成功,看起来您实际上是在尝试打开错误的文件。另外,如果你使用标准的std::ifstream打开管道,ReadFromPipe函数可以替换为std::getline

替代版本:

#include <atomic>
#include <fstream>
#include <iostream>

// made atomic and reachable from outside the function
std::atomic<bool> continueReadingFromPipe = true;

// Make it "void" if you use std::thread, "void*" if you use the C interface pthread
void pipeCommunicationThreadFunc() {
    std::string pipe = "/tmp/bash_to_c"; // corrected path
    std::string message;

    do {
        std::ifstream ps(pipe); // use std::ifstream() instead of open()

        if(ps) {  // checks that it's opened/in a good state
            while(continueReadingFromPipe) {  // continue reading while reading succeeds
                if(std::getline(ps, message)) // read a line from pipe
                    std::cout << "message: " << message << std::endl;
                else
                    break; // failed reading, break out
            }
        } else { // failed opening the pipe, abort
            continueReadingFromPipe = false;
        }
    } while(continueReadingFromPipe);  // loop and reopen the pipe
}

【讨论】:

    猜你喜欢
    • 2011-04-10
    • 2011-11-07
    • 1970-01-01
    • 2019-11-17
    • 2015-07-19
    • 1970-01-01
    • 1970-01-01
    • 2013-10-23
    • 1970-01-01
    相关资源
    最近更新 更多