是否可以读取不阻塞,但是为管道写入块?

时间:2014-05-17 07:39:04

标签: c unix select posix pipe

man 2 select在BUGS下声明以下内容:

  

在Linux下,select()可以报告套接字文件描述符为"准备好了          尽管如此,阅读",然后是后续的读取块。这可以          例如,当数据到达但检查有错误时会发生          校验和并被丢弃。可能还有其他情况          文件描述符被虚假报告为就绪。因此它可能更安全          在不应阻塞的套接字上使用O_NONBLOCK。

因此,我的read调用不需要阻塞,因此我已经标记了我的管道文件描述符O_NONBLOCK。但是,我希望write调用阻塞,直到数据写入管道。

将数据写入管道时是否可能阻塞write,但是read是否阻止了读取端?例如,仅在创建管道之后在一端调用fcntl是否合法,因为读取和写入结束具有单独的文件描述符?

1 个答案:

答案 0 :(得分:1)

您肯定可以在write的每个fcntl之前删除O_NONBLOCK标志,并在write完成后将其恢复。但是,最好始终保持套接字不阻塞,并将write置于循环中直到完成。为了不使CPU过载,请选择一个将阻塞进程的选择,直到套接字准备好写入为止。

因此,编写代码如下:

int blockingWriteOnNonBlockingFd(int fd, char *buf, int size) {
  fd_set wset, w;
  int    n, r;
  FD_ZERO(&wset);
  FD_SET(fd, &wset);
  n = 0;
  while (n < size) {
    w = wset;
    select(fd+1, NULL, &w, NULL, NULL);
    r = write(fd, buf+n, size-n);
    if (r <= 0) {
       if (r<0 && (errno == EWOULDBLOCK || errno == EAGAIN)) r = 0;
       else { /* broken connection */ break; }
    }
    n += r;
  }
  return(n);
}