【发布时间】:2017-06-19 04:53:55
【问题描述】:
我在 read_fds 中使用单个命名管道 fd 调用 select。此命名管道没有写入器,仅在非阻塞、只读模式下打开。我希望选择返回的命名管道 fd 标记为准备好读取,并且尝试从管道中读取返回 0:
从手册页上阅读:
尝试从空管道或 FIFO 中读取时:
- 如果没有进程打开管道进行写入,read() 应返回 0 以 > 指示文件结束。
但是,无限期地只选择块。为什么会这样?
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#include <string.h>
#include <stdexcept>
#include <thread>
#include <iostream>
int main()
{
char buf[4096];
// Create a named pipe
auto err = mkfifo("/tmp/whatever",0666);
if(err) {
throw std::runtime_error(
std::string("Failed to create fifo ")+
strerror(errno));
}
std::thread reader_thread(
[&](){
auto fd = open("/tmp/whatever",O_RDONLY|O_NONBLOCK);
if(fd < 0) {
throw std::runtime_error("Failed to open fifo");
}
fd_set fds;
while(1) {
FD_ZERO(&fds);
FD_SET(fd,&fds);
std::cerr << "calling select" << std::endl;
auto retval = select(fd+1,&fds,nullptr,nullptr,nullptr);
if(retval < 0) {
std::runtime_error("Failed to call select");
}
if(FD_ISSET(fd,&fds)) {
auto read_bytes = read(fd,buf,4096);
std::cerr << "read " << read_bytes << std::endl;
if(read_bytes==0) {
break;
}
}
}
close(fd);
});
reader_thread.join();
return 0;
}
【问题讨论】:
-
不要垃圾标签! C 不是 C++ 不是 C!
-
如果没有什么可读的,为什么
select要返回?? -
@Olaf> 因为 select 的手册页明确指出 “文件描述符在文件结束时也已准备就绪” 而 fifo 手册页还说 “如果引用管道写入端的所有文件描述符都已关闭,则尝试从管道读取 (2) 将看到文件结束”。这实际上是一个很好的问题。
-
我没有看到一个 openend 管道在 EOF 时从未打开写。这只会为双方开放之间的竞争条件敞开大门!
-
@Stargateur> 因为 select 的手册页说 select 观察到的确切条件是 “查看读取 (2) 是否不会阻塞”?
标签: c++ linux select posix nonblocking