假设有一个管道,
int pipe_fd[2];
pipe(pipe_fd);
我们分叉,并期望一个进程在任意时间写入管道。在其中一个进程中,我们希望能够在不阻塞的情况下检查管道的内容。
即如果不存在任何内容并且写入端保持打开状态,则典型的读取将被阻塞。我想做其他事情,甚至可能一次读一点,做一些事情,然后回来看看是否还有更多,a:
close(pipe_fd[1]);
while(1){
if(/**Check pipe contents**/){
int present_chars = 0;
while( read(pipe_fd[0],&buffer[present_chars],1) != 0)
++present_chars;
//do something
}
else
//do something else
}
你的逻辑是错误的,当字符用完时,
read
不会返回0;相反,它会阻塞,直到收到更多,除非您将文件置于非阻塞模式,但随后它将返回 -1 并将 errno
设置为 EWOULDBLOCK
或 EAGAIN
,而不是返回 0。唯一一次 当大小参数为 0 或已到达文件末尾时,read
可以ever 返回 0。并且,对于管道,文件结束意味着管道的写入端已关闭;文件结束状态不会仅仅因为还没有任何可用输入而发生。
话虽如此,最简单的检查方法是:
if (poll(&(struct pollfd){ .fd = fd, .events = POLLIN }, 1, 0)==1) {
/* data available */
}
但是除非您使用非阻塞模式,否则您需要在每次读取操作之前进行此检查。将更大的缓冲区传递给
read
而不是一次一个字节地传递,可以消除大部分检查成本。
您可以通过
read()
功能检查是否有数据要读取。来自read(3)
:
When attempting to read from an empty pipe or FIFO:
* If some process has the pipe open for writing and
O_NONBLOCK is set, read() shall return -1 and set
errno to [EAGAIN].
* If some process has the pipe open for writing and
O_NONBLOCK is clear, read() shall block the calling
thread until some data is written or the pipe is
closed by all processes that had the pipe open for
writing.
The read() function shall fail if:
EAGAIN or EWOULDBLOCK
The file descriptor is for a socket, is marked
O_NONBLOCK, and no data is waiting to be received.
因此,如果您设置了
O_NONBLOCK
,只需调用 read()
,您就可以判断是否要在管道上读取某些内容。
提醒一下,来自
open(3)
:
SYNOPSIS
int open(const char *path, int oflag, ... );
DESCRIPTION
Values for oflag are constructed by a
bitwise-inclusive OR of flags from the following
list, defined in <fcntl.h>. Applications shall
specify exactly one of the first three values
(file access modes) below in the value of oflag:
O_NONBLOCK [...]
希望有帮助。
R.. 的答案很好,但是 poll 返回在“revents”中设置了标志的文件描述符结构的数量。如果您可以从
fd
读取,则该值为 1,但如果设置了任何错误标志,该值为 1。这意味着 R.. 的答案会说如果管道进入错误状态,则该管道是可读的。更可靠的检查可能是这样的:
bool canReadFromPipe(){
//file descriptor struct to check if POLLIN bit will be set
//fd is the file descriptor of the pipe
struct pollfd fds{ .fd = fd, .events = POLLIN };
//poll with no wait time
int res = poll(&fds, 1, 0);
//if res < 0 then an error occurred with poll
//POLLERR is set for some other errors
//POLLNVAL is set if the pipe is closed
if(res < 0 || fds.revents & (POLLERR | POLLNVAL))
{
//an error occurred, check errno
}
return fds.revents & POLLIN;
}