在管道上执行read()不会阻塞

3

我有下面的代码片段,在其中我使用管道进行父子进程之间的双向读写。

据我所知,如果我不使用O_NONBLOCK,则读操作应该会阻塞直到数据从另一端被写入管道中。

然而,我注意到父进程端的读取没有被阻塞。我知道因为我正在gdb中进行调试,所以我在子进程的第一个语句中放置了一个睡眠。

为什么父进程的read()在这里没有被阻塞?还有,我是否需要做其他事情来同步两个进程之间的读写如下?

typedef struct
{
    int x;
    int y;
}PayLoad;

PayLoad pl;
bool b = false;

int pipe_fds[2];


void p(int i, int j)
{
   pl.x = i;
   pl.y = j;

   pipe(pipe_fds);
   pid_t cpid = fork();

   if (cpid == 0) // child process
   {
       std::this_thread::sleep_for(std::chrono::seconds(100)); // just for debugging
       close(pipe_fds[1]);
       read(pipe_fds[0], &pl, sizeof(Payload));
       //... do some processing on read data

       close(pipe_fds[0]);
       write(pipe_fds[1], &b, sizeof(bool));
       close(pipe_fds[1]);
   }
   else if (cpid > 0) // parent process
   {
       close(pipe_fds[0]);
       write(pipe_fds[1], &pl, sizeof(Payload));
       close(pipe_fds[1]);
       read(pipe_fds[0], &b, sizeof(bool));  <------ did not block!
       close(pipe_fds[0]);
   }
}

它返回什么?检查返回值!当实际上是C++时,不要标记为C。 - Iharob Al Asimi
谢谢。目前只需添加代码以检查从读取返回的内容。 - user2930006
4
在读取之前关闭描述符——实际上,良好的错误处理会为你节省一些时间,而且在将来也是如此。 - Erki Aring
这是因为我正在处理一个cpp项目,而这段代码就是在cpp文件中。基本上,我有一个cpp线程,它以前在调用外部库时会发生死锁。因此,我把那个容易卡住的代码放进一个进程里,这样我就可以杀死/重新启动这个卡住的进程了。 - user2930006
@ErkiA(和kadina)..谢谢。确实,描述符正在关闭。读取器在读取之前先关闭管道的写入端口,同样地,写入器在写入之前关闭管道的读取端口。然而,在上述情况下,使用同一管道,读取器随后想要写入,因此写入器随后想要读取,我该怎么办? - user2930006
显示剩余3条评论
1个回答

1
如果设置了O_NONBLOCK,read()将返回-1并将errno设置为[EAGAIN]。
真正的问题是在使用文件描述符之前关闭它们。例如,在子进程中,您正在关闭pipe_fds[1]并使用它来写入某个值。在父进程中,您正在关闭pipe_fds[0]并使用它来读取某个值。一旦进程关闭了文件描述符,进程就不应该再使用它进行读取或写入。通常,管道的概念是一个进程(父进程或子进程)将使用由管道创建的文件描述符之一进行写入,另一个进程(父进程或子进程)将使用另一个文件描述符读取数据。

感谢Erki A和kadina。确实,描述符已被关闭。读取器在读取之前先关闭管道的写入端口,同样地,写入器在写入之前关闭管道的读取端口。然而,在上述情况下,使用同一管道,读取器随后想要写入,因此写入器随后想要读取,我该怎么办? - user2930006
@user2930006:你需要使用两个管道。 - kadina

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接