select()返回无效参数

select()返回无效参数,c,unix,select,pipe,C,Unix,Select,Pipe,我正在成功地从另一个线程读取管道,并打印输出(在ncurses窗口中) 出于各种原因,我需要一次只处理一个字符,并且我在FD上使用select()作为管道的读取端,同时使用一些其他FD(如stdin) 我的想法是,仅当管道即将准备好读取时才尝试从管道读取,而不是处理任何输入。这似乎在起作用——至少从一开始是这样。select()设置fd_集,如果设置了fd_,则从fd读取1字节。但是select()说yes的次数太多,read()就会阻塞 所以我的问题是-如果后续的read()阻塞,为什么sel

我正在成功地从另一个线程读取管道,并打印输出(在ncurses窗口中)

出于各种原因,我需要一次只处理一个字符,并且我在FD上使用select()作为管道的读取端,同时使用一些其他FD(如stdin)

我的想法是,仅当管道即将准备好读取时才尝试从管道读取,而不是处理任何输入。这似乎在起作用——至少从一开始是这样。select()设置fd_集,如果设置了fd_,则从fd读取1字节。但是select()说yes的次数太多,read()就会阻塞

所以我的问题是-如果后续的read()阻塞,为什么select()会报告fd已准备好读取

(大约)如果管道的另一端连接到分叉流程(如果有帮助的话)时,相同的代码工作正常

我可以根据要求发布代码,但这是bog标准。设置fd_集,复制它,选择复制,如果fd已设置,则调用从同一fd读取字节的函数。。。否则,恢复fd_集副本

编辑:根据请求,以下是代码:

设置我的fd_集:

fd_set fds;
FD_ZERO(&fds); 
FD_SET(interp_output[0], &fds);
FD_SET(STDIN_FILENO, &fds);
struct timeval timeout, tvcopy; timeout.tv_sec=1;
int maxfd=interp_output[0]+1; //always >stdin+1
fd_set read_fds;
FD_COPY(&fds, &read_fds);
在循环中:

if (select(maxfd, &read_fds, NULL, NULL, &timeout)==-1) {perror("couldn't select"); return;}
if (FD_ISSET(interp_output[0], &read_fds)) {
    handle_interp_out();
} else if (FD_ISSET(STDIN_FILENO, &read_fds)) {
//waddstr(cmdwin, "stdin!"); wrefresh(cmdwin);
    handle_input();
}

FDCOPY(&fds, &read_fds);
handle_interp_out():

编辑2:写入代码只是用fdopen打开的文件*上的一个fprintf(interp_输出[1],“w”)-这是在另一个线程中。我要做的就是我的“prompt>”——它正确地打印了所有这些内容,但又进行了一次不应该的迭代。我关闭了缓冲,这给我带来了其他问题

编辑3:这已经成为我调用select()的一个问题。看起来,它立即返回-1,并且errno被设置为“invalid argument”。read()不知道这一点,只是继续。我的select()有什么问题?我已经更新了代码并更改了标题以更准确地反映问题

编辑4:所以现在我完全糊涂了。不知为什么,.tv_sec=1的超时值不好。通过去掉它,代码工作得很好。如果有人有什么理论,我洗耳恭听。我只想将其保留为NULL,除非该线程需要定期进行更新。

答案是“不会”。你所描述的行为永远不会发生。有些事情出了问题

我曾多次遇到过类似的情况,通常结果是,在其他地方有一个愚蠢的打字错误或剪切粘贴错误,导致了我错误诊断的行为

如果你发布你的代码,也许我们可以更好地帮助你——请发布写代码和读代码

也考虑使用异步IO,即使仅用于调试目的。如果您怀疑正在发生的事情确实正在发生,则read()将返回eWoldBlock


另外,您说您正在复制fd_集。怎么用?你能发布你的代码吗?

这是正确的。例如,请参见Linux中的select()手册页:

在Linux下,select()可能会将套接字文件描述符报告为“ready for reading”,但随后的读取会阻塞


唯一的解决方案是使用非阻塞插座。

根据手册页:

在出现错误时,返回-1,并正确设置errno;集合和超时变得未定义,因此在发生错误后不要依赖它们的内容

您没有检查select()中的返回代码

最可能的解释是select()被中断(errno=EINTR),因此返回一个错误,FD位仍然设置在“读取”FD_集中,给出您看到的行为


顺便说一句,在标准/系统/公共函数之后命名变量是一个非常糟糕的主意。“read_fds”比“read”好得多。

为了绝对保证读取不会阻塞,您必须在fd上设置O_NONBLOCK

由于没有设置整个时间结构,几乎肯定会导致select错误。你只是在设置秒数。另一个字段将包含从堆栈中拾取的垃圾数据

使用结构初始化。这将保证其他字段设置为0

它看起来是这样的:

struct timeval timeout = {1, 0};

另外,在select循环中,您应该知道Linux会将剩余时间写入超时值。这意味着,除非将值重置为1秒,否则下一次循环的时间不会是1秒。

一次过多会发生什么?抱歉-选择(maxfd,&read,…)将FD设置在读取集中,但在同一FD块上的后续读取(…,1)请看,我不认为我疯了。在上面发布代码-if(ch>0)的主体只是将字符放在屏幕上;这很有效。fd_集合只是局部变量-分配它们应该复制。你可以知道现在是星期一早上。我看错了你的密码,贴出了一个愚蠢的答案。等一下。无论如何,您应该检查select()的返回值。如果select()失败(可能是由于中断),它可能还没有修改fd_集。我没有使用套接字,只是使用普通管道。这是我不知道的,但我不认为这会给我带来问题。我错过了烟斗的事。。。SorryIt返回错误,但EINVAL-参数无效。我还将fd_集重命名为read_fds(我怎么会错过它呢?),但这没有帮助。这解决了我的timeval问题-我忘记了堆栈数据。但这实际上一直是我的原始问题,因为它使select()返回EINVAL,而这不会影响fd_集,我正在检查fd_集。所以感谢Alastair,检查错误绝对是我应该检查的事情——但这是我最初的问题。你回答的第一句话是正确的,但这只是因为有缺陷的实现(Linux)拒绝修复它们的错误。根据POSIX,
select
不允许返回套接字fd是可读的,除非有数据要
read
@R,请参阅我的答案。错误时,和fd_集合的返回内容和超时结构未定义。他
struct timeval timeout = {1, 0};