C read()在linux中等待吗?

C read()在linux中等待吗?,c,linux,C,Linux,我正在学习Linux中的pipe()系统调用。以下是我有疑问的代码片段: #define MSGSIZE 16 char* msg1 = "hello, world #1"; char* msg2 = "hello, world #2"; char* msg3 = "hello, world #3"; int main() { char inbuf[MSGSIZE]; int p[2], i; if (pip

我正在学习Linux中的pipe()系统调用。以下是我有疑问的代码片段:

#define MSGSIZE 16
char* msg1 = "hello, world #1";
char* msg2 = "hello, world #2";
char* msg3 = "hello, world #3";

int main()
{
    char inbuf[MSGSIZE];
    int p[2], i;

    if (pipe(p) < 0)
        exit(1);

    int pid=fork();
    if(pid==0){
        sleep(2);  ///Making parent process sleep so that child process moves ahead
        write(p[1], msg1, MSGSIZE);
        write(p[1], msg2, MSGSIZE);
        write(p[1], msg3, MSGSIZE);
        printf("Done writing");
    }
    else{
        printf("child process\n");
        for (i = 0; i < 3; i++) {
            read(p[0], inbuf, MSGSIZE);
            printf("%s\n", inbuf);
        }
    }
    return 0;
}
正如我们所看到的,子进程在完成写入调用之前已经启动。在这里,read call似乎在等待什么。我在手册页中找不到有关此行为的文档。
有人能简单地解释一下这里发生了什么吗?

关键词:同步

终端的输出由两个进程共享。终端是如何在内部处理同步的,谁知道呢,但是您可以同步进程的输出(例如,通过共享内存和互斥或信号量)。因此,不要依赖于输出的顺序,即先调用什么,谁在等待谁

或者简单地为每次调用
printf
使用一个时间戳

我在这里回答了一个类似的问题:。

默认情况下,read()会一直阻塞,直到有可用的输入或输入结束

POSIX(IEEE Std 1003-1)标准规定,管道至少可以容纳512字节的数据。(这意味着write()将立即成功,即使数据仍在管道中,另一端尚未读取。)


主进程将数据写入管道并立即退出。由于子进程的读取端仍处于打开状态,因此它可以稍后读取主进程写入的数据。

我冒昧地对您的代码进行了一些润色,特别是:

父进程和子进程 我修改了
IF
语句以正确标识父进程和子进程。从fork()手册页,关于它的返回值:

成功时,子进程的PID将在 父级,并且在子级中返回0。失败时,-1为 在父进程中返回,未创建子进程,错误号为 适当地设置

在这种情况下,这没什么大不了的,但肯定会导致一些问题

关闭管道 我在未使用和完成读/写时都关闭了管道末端。看看为什么它在这里很重要:

退出和等待 我让家长等待孩子的终止,以免留下一个孤立的过程(在更复杂和极端的情况下)导致系统资源匮乏

代码如下:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/wait.h>

#define MSGSIZE 16

char* msg1 = "hello, world #1";
char* msg2 = "hello, world #2";
char* msg3 = "hello, world #3";

int main()
{
  char inbuf[MSGSIZE];
  int p[2], i;

  if (pipe(p) < 0)
    exit(1);

  int pid = fork();
  if (pid > 0) {
    // Parent process
    
    close(p[0]);  // Closing unused pipe

    //sleep(2);  
    write(p[1], msg1, MSGSIZE);
    write(p[1], msg2, MSGSIZE);
    write(p[1], msg3, MSGSIZE);
    close(p[1]);  // Closing pipe after all writes are done
    printf("Parent done writing\n");

    wait(NULL);
  } else if (pid == 0) {
    // Child process

    close(p[1]);  // Closing unused pipe
    printf("Child process\n");
    for (i = 0; i < 3; i++) {
      read(p[0], inbuf, MSGSIZE);
      printf("%s\n", inbuf);
    }
    close(p[0]);

    exit(0);  // Child has terminated succesfully, exit.

  } else {
    fprintf(stderr, "Fork error.\n");
    return 1;
  }

  return 0;
}
#包括
#包括
#包括
#包括
#定义MSGSIZE 16
char*msg1=“你好,世界1”;
char*msg2=“你好,世界2”;
char*msg3=“你好,世界3”;
int main()
{
char inbuf[MSGSIZE];
int p[2],i;
如果(管道(p)<0)
出口(1);
int-pid=fork();
如果(pid>0){
//父进程
关闭(p[0]);//关闭未使用的管道
//睡眠(2);
写入(p[1],msg1,MSGSIZE);
写入(p[1],msg2,MSGSIZE);
写入(p[1],msg3,MSGSIZE);
close(p[1]);//完成所有写入操作后关闭管道
printf(“父级完成写入\n”);
等待(空);
}否则如果(pid==0){
//子进程
关闭(p[1]);//关闭未使用的管道
printf(“子进程”);
对于(i=0;i<3;i++){
读取(p[0],inbuf,MSGSIZE);
printf(“%s\n”,inbuf);
}
接近(p[0]);
退出(0);//子项已成功终止,退出。
}否则{
fprintf(stderr,“Fork error.\n”);
返回1;
}
返回0;
}

简单的答案是,
读取
会等待一些输入可用

更准确地说,文件可以在阻塞或非阻塞模式下打开。阻塞模式是默认模式。您可以通过将
flags
参数中的
O_NONBLOCK
传递到
open
(例如
open(filename,O_RDONLY | O_NONBLOCK)
)或在打开文件后调用
fcntl(fd,F_SETFL,O_NONBLOCK)
,来选择非阻塞模式

在阻塞模式下,
读取
通常会等待,直到读取至少一个字节。请注意,它不会等到读取了请求的字节数,即使有那么多字节可用。一次
读取
调用返回多少字节取决于进程调度器的突发奇想。“正常”意味着您可以像

do n = read(…);
while (n > 0 || (n < 0 && errno == EINTR));
do n=read(…);
而(n>0 | |(n<0&&errno==EINTR));
并且要确信这不会是一个紧密的循环。注意,
errno==EINTR
,这表示在读取任何内容之前,
read
被中断。(返回0并不表示这一点,因为返回0表示文件结束,因此返回0更符合逻辑。)

如果文件处于非阻塞模式,则未读取任何内容的另一种情况是
errno==EAGAIN
。在非阻塞模式下,如果没有可用数据,
read
会立即返回,因此类似于上述循环的循环将是错误的


所有这一切也适用于
写入
,除了0表示文件结束。

是的,它在返回之前等待输入。除非描述符是非阻塞的,
read()
将阻塞,直到有可用的输入(或错误)。在文档中搜索
O_NONBLOCK
标志。或中断(检查
errno
以查看
EINTR
)。顺便说一句:您应该检查函数
read
write
的返回值。不能保证它总是写入或读取完整的消息。可能需要多次重复调用以读取或写入其余部分。
do n = read(…);
while (n > 0 || (n < 0 && errno == EINTR));