假设有一个管道,
int pipe_fd[2];
pipe(pipe_fd);
我们fork,并期望一个进程将在任意时间写入管道。在其中一个过程中,我们希望能够在不阻塞的情况下检查管道的内容。
即。如果没有任何内容并且写入结束保持打开,则典型读取将阻塞。我想去做其他的事情,甚至可能一次读一些,做一些事情,然后检查一下是否还有更多,la:
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
}
答案 0 :(得分:10)
你的逻辑是错误的,read
在字符用完时不会返回0;相反,它会阻塞,直到它收到更多,除非你把文件置于非阻塞模式,但它会返回-1并将errno
设置为EWOULDBLOCK
或EAGAIN
而不是返回0.当size参数为0或达到文件结尾时,唯一一次read
可以永远返回0。并且, for pipes ,end-of-file表示管道的写入端已经关闭;文件结束状态不会因为没有任何可用输入而发生。
据说,最简单的检查方法是:
if (poll(&(struct pollfd){ .fd = fd, .events = POLLIN }, 1, 0)==1) {
/* data available */
}
但除非您使用非阻塞模式,否则您需要在每次读取操作之前进行此检查。将较大的缓冲区传递给read
而不是一次一个字节,这将消除大部分检查成本。
答案 1 :(得分:4)
您可以使用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 [...]
我希望它有所帮助。
答案 2 :(得分:1)
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;
}