Bad*_*ild 5 c++ file popen nonblocking c++11
我正在通过popen()执行长时间运行(通常是阻塞的)命令:"ls -R /"
问题:popen()读入你提供的缓冲区,它似乎试图在返回之前填充ENTIRE缓冲区.这导致它经常阻塞(如果你的缓冲区很大).
解决方案似乎是使基础fd无阻塞.当我这样做时,popen()仍会阻塞,通常每次约1秒.为什么会这样?
这是我的代码.确保使用-std = c ++ 11进行编译:
#include <cstdio>
#include <iostream>
#include <sys/time.h>
#include <unistd.h>
#include <fcntl.h>
static constexpr size_t SIZE = 65536;
struct Time
{
friend std::ostream &operator<<(std::ostream &os, Time const &t)
{
(void)t;
timeval tv;
gettimeofday(&tv, nullptr);
os << tv.tv_sec << "." << std::fixed << tv.tv_usec << " ";
return os;
}
};
int main()
{
FILE *file;
file = popen("ls -R /", "r");
if(!file)
{
std::cerr << "Could not open app: " << errno;
return -1;
}
// Make it non-blocking
int fd = fileno(file);
fcntl(fd, F_SETFL, O_NONBLOCK);
char buffer[SIZE];
Time t;
while(true)
{
int rc = fread(buffer, 1, SIZE, file);
if(rc <= 0)
{
if(EAGAIN == errno)
{
usleep(10);
continue;
}
std::cerr << t << "Error reading: " << errno << std::endl;
break;
}
std::cerr << t << "Read " << rc << std::endl;
}
pclose(file);
return 0;
}
Run Code Online (Sandbox Code Playgroud)
输出(注意它们相隔大约1秒,即使fd是非阻塞的,我在循环中只有10mS的暂停):
1429625100.983786 Read 4096
1429625101.745369 Read 4096
1429625102.426967 Read 4096
1429625103.185273 Read 4096
1429625103.834241 Read 4096
1429625104.512131 Read 4096
1429625105.188010 Read 4096
1429625105.942257 Read 4096
1429625106.642877 Read 4096
Run Code Online (Sandbox Code Playgroud)
首先,你应该使用read而不是fread.stdio函数在OS之外有自己的缓冲层,因此它们甚至可以阻止非阻塞文件描述符.使用read避免这种情况.
其次,您需要停止ls缓冲其输出.链接到glibc的程序的默认行为是在stdout连接到TTY时使用行缓冲,在连接到管道或重定向到文件时使用完全缓冲.完全缓冲意味着仅在4KB缓冲区填满时才刷新输出,而不是每次输出换行时刷新.
您可以使用stdbuf覆盖此行为.请注意,它仅适用于使用C流并链接到glibc的程序.这是大多数程序,但不是全部.
popen("stdbuf -oL ls -R /", "r");
Run Code Online (Sandbox Code Playgroud)