【问题标题】:Make std::cout do not fail with O_NONBLOCK or make stdin O_NONBLOCK keeping stdout blocking?使 std::cout 不会因 O_NONBLOCK 失败或使 stdin O_NONBLOCK 保持标准输出阻塞?
【发布时间】:2020-10-28 01:21:14
【问题描述】:
#include <iostream>
#include <unistd.h>
#include <fcntl.h>
using namespace std;

int main(){
        // Make stdin non-blocking
        fcntl(STDIN_FILENO, F_SETFL, fcntl(STDIN_FILENO, F_GETFL) | O_NONBLOCK);

        printf("stdout O_NONBLOCK is: %d\n", fcntl(STDOUT_FILENO, F_GETFL) & O_NONBLOCK);
        printf("stdin O_NONBLOCK is: %d\n",  fcntl(STDIN_FILENO , F_GETFL) & O_NONBLOCK);

        for(int i=0; i<16; i++){
            cout<<"  "<<"fgvbhln;j;jblhcbwnoi wiejnocje ocweo cewoj coj weoj cowejojewohewouspuweoche njwpihbeh wjo erouhep hv reough er "<<endl;
        }
        bool cerrfail=cerr.fail(), coutfail=cout.fail();
        flush(cout); flush(clog); flush(cerr);
        cout.clear(); cerr.clear(); clog.clear();
        cerr<<"\ncerr.fail():"<<cerrfail<<" cout.fail():"<<coutfail<<endl;
}

可能的输出:

编译器 G++ 9.3
MacOS Mojave 10.14.6

stdout O_NONBLOCK is: 4
stdin O_NONBLOCK is: 4
  fgvbhln;j;jblhcbwnoi wiejnocje ocweo cewoj coj weoj cowejojewohewouspuweoche njwpihbeh wjo erouhep hv reough er 
  fgvbhln;j;jblhcbwnoi wiejnocje ocweo cewoj coj weoj cowejojewohewouspuweoche njwpihbeh wjo erouhep hv reough er 
  fgvbhln;j;jblhcbwnoi wiejnocje ocweo cewoj coj weoj cowejojewohewouspuweoche njwpihbeh wjo erouhep hv reough er 
  fgvbhln;j;jblhcbwnoi wiejnocje ocweo cewoj coj weoj cowejojewohewouspuweoche njwpihbeh wjo erouhep hv reough er 
  fgvbhln;j;jblhcbwnoi wiejnocje ocweo cewoj coj weoj cowejojewohewouspuweoche njwpihbeh wjo erouhep hv reough er 
  fgvbhln;j;jblhcbwnoi wiejnocje ocweo cewoj coj weoj cowejojewohewouspuweoche njwpihbeh wjo erouhep hv reough er 
  fgvbhln;j;jblhcbwnoi wiejnocje ocweo cewoj coj weoj cowejojewohewouspuweoche njwpihbeh wjo erouhep hv reough er 
  fgvbhln;j;jblhcbwnoi wiejnocje ocweo cewoj coj weoj cowejojewohewouspuweoche njwpihbeh wjo erouhep hv reough er 
  fgvbhln;j;jblhcbwnoi wiejnocje ocweo cewoj coj weoj cowejojewohewouspuweoche njwpihbeh wjo ero
cerr.fail():0 cout.fail():1

因为fcntl(STDIN_FILENO, F_SETFL, fcntl(STDIN_FILENO, F_GETFL) | O_NONBLOCK);而失败

为什么?如何解决保持标准输入非阻塞的问题?

更新。 为什么?因为设置 stdin O_NONBLOCK 也会使 stdout O_NONBLOCK。并且 std::out 在其内部接收到一些 ASYNC 错误代码(如 ETRYAGAIN)。

我看到了两种解决方案:

  • 使 std::cout 不会因 O_NONBLOCK 而失败
  • 让标准输入 O_NONBLOCK 保持标准输出阻塞?

更新2。 该问题仅出现在 MacOS 上。不在 Linux amd64 上,也不在 Linux MIPS (Atheros) 上。

【问题讨论】:

  • 您的通话后标准输出是否也是非阻塞的? stackoverflow.com/q/23865898/1133144
  • 是的。它将非阻塞设置为stdout O_NONBLOCK is: 4 stdin O_NONBLOCK is: 4
  • 您使用的是什么编译器、版本、编译器选项?你在哪个平台?您使用的是什么 C 和 C++ 标准库的实现?我认为,如果这是特定于 OSX 的,请考虑使用 OSX 对其进行标记。我无法使用 glibc 在 linux 上重现,(在 linux O_NONBLOCK = 2048 上)。
  • @KamilCuk,感谢您的回复,我添加了有关我的系统的详细信息。
  • 您的更新并没有真正解释为什么您希望stdout 是非阻塞的。这样做有什么好处?如果尝试输出会生成错误代码,那么听起来您遇到了 X-Y 问题,应该改正 that

标签: c++ stdout iostream nonblocking fcntl


【解决方案1】:

标准流不支持非阻塞文件描述符,它们超出了 C++ 标准的范围。

如果你坚持在标准流中使用非阻塞文件描述符,那么你需要实现一个可以读/写非阻塞文件描述符的流缓冲区。您可以通过派生std::basic_streambuf 并实现其虚函数从头开始执行此操作,或者使用出色的Boost.Iostreams 来大大减少您必须编写的样板代码的数量和复杂性。然后通过调用std::basic_ios&lt;&gt;::rdbuf,将std::coutstd::cin 和朋友的缓冲区替换为您的特殊流缓冲区。

即便如此,使用std::istreamstd::ostream 接口您也无法区分文件结尾和EAGAIN


您可能想详细说明您要解决的问题,因为您当前的解决方案会产生更多问题。

【讨论】:

  • 谢谢。我找到了一种拒绝非阻塞标准输入的方法,现在标准输出工作正常。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-05-30
  • 1970-01-01
  • 2010-11-19
  • 2016-12-15
相关资源
最近更新 更多