Pri*_*tic 4 c++ linux select posix nonblocking
我在 read_fds 中使用单个命名管道 fd 调用 select。该命名管道没有写入器,并且仅以非阻塞、只读模式打开。我希望 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;
}
Run Code Online (Sandbox Code Playgroud)
来自 POSIX 文档select:
当对 O_NONBLOCK 清除的输入函数的调用不会阻塞时,无论该函数是否成功传输数据,描述符都应被视为已准备好读取。(该函数可能会返回数据、文件结束指示或指示其被阻塞的错误以外的错误,并且在每种情况下,描述符应被视为已准备好读取。
...
如果没有一个选定的描述符已准备好执行请求的操作,则 pselect() 或 select() 函数将阻塞,直到至少一个请求的操作准备就绪、发生超时或被信号中断。
从pipe(7)联机帮助页(这是 FIFO 的基础对象):
如果引用管道写入端的所有文件描述符都已关闭,则尝试从管道读取(2)将看到文件结尾(读取(2)将返回0)。
注意现在完成时的使用!这意味着必须首先在两侧打开 FIFO ,然后在写入器侧(对于您的应用程序)关闭以生成条件EOF。
那么,除非 fifo 最终被作者关闭,否则为什么要select返回呢?(fifo-) 文件本身的设置是无关紧要的,这是有充分理由的:当使用最有效的方法一次读取多个字节时,它会在两侧打开之间引入竞争条件。这是命令管道的正常方式:启动读取器进程,然后启动写入器(使用命名管道时,这通常是完全不相关的程序)。
如果您想select早点返回,请使用timeout参数。但通常情况下,我们使用一个单独的线程,该线程可以通过信号终止(select有关更多信息,请参阅手册页)。
作为旁注:Linux/POSIX 的一个好处是,无论您使用 FIFO 还是文件或麦克风驱动程序,这并不重要。
| 归档时间: |
|
| 查看次数: |
742 次 |
| 最近记录: |