有没有一种方法可以在管道/终端/等设备上以非阻塞模式进行单 read()
,也可以在{{1} }?
我需要这样做的原因是因为我无法找到保证recv(MSG_DONTWAIT)
或read()
返回的文件描述符上的select()
不会< / em>块。
我知道可以使用poll()
使文件描述符不阻塞,但这将全局更改该文件描述符的模式,而不仅仅是在调用线程/进程中。例如:
fcntl(fd, F_SETFL, fcntl(fd, F_GETFL) | O_NONBLOCK)
这也将使fd不受 的读写影响,这可能会使在同一fd上执行相反操作的另一个进程造成混乱,例如:
% perl -MFcntl=F_SETFL,F_GETFL,O_NONBLOCK -e 'fcntl STDIN, F_SETFL, fcntl(STDIN, F_GETFL, 0) | O_NONBLOCK; select undef, undef, undef, undef'
^Z # put it in the background
% cat
cat: -: Resource temporarily unavailable
我想到的一种方法是在启动和non_blocking_read | filter | blocking_write
时保存文件状态标志,并在退出和SIGCONT
时保存文件状态标志(这与termios设置一样),但是这是非常有限的,容易发生竞争,并且在程序异常退出的情况下会留下混乱。
在每个SIGTSTP
之前/之后使用fcntl()
进行保存/恢复也很丑陋,并且可能还会有其他问题。与read()
之前的ioctl(FIONREAD)
相同(我什至不确定它是否可以在任何fd上可靠地工作;不过,朝着这个方向的保证还是值得欢迎的。)
即使使用特定于系统的解决方案(例如linux或仅bsd),我也会感到满意。
供参考,here是关于在linux中修复它的讨论;但是,这个主意似乎并没有解决。
答案 0 :(得分:0)
仅Linux的解决方案是通过以下方式重新打开文件描述符 “ / dev / stdin” |“ / dev / tty” |“ / dev / fd / $ fd” 。
C示例:
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
int main()
{
int fd;
char buf[8];
int flags;
if(0>(fd=open("/dev/stdin", O_RDONLY))) return 1;
if(0>(flags = fcntl(fd,F_GETFL))) return 1;
if(0>(flags = fcntl(fd,F_SETFL,flags|O_NONBLOCK))) return 1;
sleep(3);
puts("reading");
ssize_t nr = read(fd, buf, sizeof(buf));
printf("read=%zd\n", nr);
return 0;
}
与dup
关联的文件描述符不同,重新打开的文件描述符将具有独立的文件状态标志。