有人能解释一下管道缓冲区死锁吗?
Python文档中提到关于Popen的内容:
警告:使用communicate()而不是.stdin.write、.stdout.read或.stderr.read,以避免由于其他操作系统管道缓冲区填满而导致的死锁,这会阻塞子进程。
现在,我想弄明白这种死锁是怎么发生的,以及为什么会发生。
我的理解是:子进程会向标准输出(stdout)或标准错误(stderr)输出一些内容,这些内容会先被暂时存储在一个缓冲区中。当这个缓冲区满了之后,内容就会被发送到子进程的标准输出或标准错误中,然后通过管道传递给父进程。
根据文档的说法,管道有自己的缓冲区,当这个缓冲区满了或者子进程结束时,内容才会被发送到父进程。
不管是有管道缓冲区还是没有,我并不完全明白死锁是怎么发生的。我能想到的唯一情况是某种“全局”的操作系统管道缓冲区,进程们会争抢这个缓冲区,这听起来有点奇怪。还有一种可能是多个进程共享同一个管道,这种情况本身是不应该发生的。
有人能帮我解释一下吗?
2 个回答
死锁会发生在两个缓冲区(标准输入和标准输出)都满的时候:你的程序在等着往外部程序写更多的输入,而外部程序则在等着你先从它的输出缓冲区读取数据。
解决这个问题的方法是使用非阻塞输入输出,并合理安排缓冲区的优先级。你可以尝试自己去实现这个功能,但其实communicate()
这个方法已经为你做好了这些事情。
小心,这里有一个微妙的错误。
我的理解是:子进程会向标准输出(stdout)或标准错误(stderr)发送一些东西,这些内容会先被暂时存储在一个缓冲区里。当这个缓冲区满了之后,内容才会被发送到子进程的标准输出或标准错误,然后通过管道传递给父进程。
这个缓冲区是父进程和子进程共享的。
子进程向标准输出发送内容,而这个标准输出的缓冲区正是父进程应该读取的地方。
当缓冲区满了,写入操作会停止,直到缓冲区被清空。对于管道来说,"刷新"并没有什么意义,因为两个进程共享同一个缓冲区。
将内容刷新到磁盘意味着设备驱动程序必须将字节传送到设备上。将内容刷新到套接字则是告诉TCP/IP停止等待累积缓冲区并发送数据。将内容刷新到控制台则意味着停止等待换行符,并通过设备驱动程序将字节发送到设备。