使 std::cout 不会因 O_NONBLOCK 失败或使 stdin O_NONBLOCK 保持 stdout 阻塞?

Make std::cout do not fail with O_NONBLOCK or make stdin O_NONBLOCK keeping stdout blocking?

#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;
}

可能的输出:

Compiler 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 也会使标准输出 O_NONBLOCK。 std::out 在其内部收到一些 ASYNC 错误代码(如 ETRYAGAIN)。

我看到两个解决方案:

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

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

如果您坚持对标准流使用非阻塞文件描述符,那么您需要实现一个可以read/write 非阻塞文件描述符的流缓冲区。您可以通过派生 std::basic_streambuf 并实现其虚函数或使用出色的 Boost.Iostreams 从头开始 以大大减少您必须编写的样板代码的数量和复杂性。然后通过调用 std::basic_ios<>::rdbuf.

std::coutstd::cin 和朋友的缓冲区替换为您的特殊流缓冲区

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


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