这是一个依赖于缓冲的并发错误:
$ stdbuf -o 0 ./pipe
child-0 (pid 864370) receives: 0
child-1 (pid 864371) receives: 1
child-2 (pid 864372) receives: 2
$ stdbuf -o 0 ./pipe > out && cat out
child-0 (pid 864355) receives: 0
child-1 (pid 864356) receives: 1
child-2 (pid 864357) receives: 2
$ stdbuf -o L ./pipe
child-0 (pid 866493) receives: 0
child-1 (pid 866494) receives: 1
child-2 (pid 866495) receives: 2
$ stdbuf -o L ./pipe > out && cat out
child-0 (pid 866501) receives: 0
child-1 (pid 866502) receives: 1
child-2 (pid 866503) receives: 2
$ stdbuf -o 4096 ./pipe
child-0 (pid 864399) receives: 0
child-1 (pid 864400) receives: 1
child-2 (pid 864401) receives: 2
child-0 (pid 864399) receives: 0
child-1 (pid 864400) receives: 1
child-0 (pid 864399) receives: 0
$ stdbuf -o 4096 ./pipe > out && cat out
child-0 (pid 864385) receives: 0
child-1 (pid 864386) receives: 1
child-2 (pid 864387) receives: 2
child-0 (pid 864385) receives: 0
child-1 (pid 864386) receives: 1
child-0 (pid 864385) receives: 0
请注意,这种类型的缓冲只影响
printf()
不
read()
或
write()
。
当没有缓冲时(
stdbuf -o 0
),或者当每行都进行缓冲时(
stdbuf -o L
),
打印()
将在打印后立即刷新其写入缓冲区。
重定向到文件时,缓冲区要大得多(例如4k字节),并且
打印()
不会刷新该缓冲区。
然后你
fork()
但是
打印()
的缓冲区是用户空间的东西,内核并不知道,所以在
分叉()
父级和子级都有缓冲区的副本。
在2个这样的叉之后,缓冲区包含所有3个打印,第三个子将打印这些打印。
但第二个孩子没有意识到第三个孩子已经打印了所有内容,它将打印缓冲区,其中包含前两个打印。
类似地,第一个子将打印其缓冲区,该缓冲区合法地仅包含其自己的打印。
这就是你得到0、1、2(来自第三个孩子)、0、1(来自第二个孩子)和0(来自第一个孩子)的方式。
你可以通过
strace
(1) 通过检查写入的字节数:
$ strace -o /tmp/trace -f ./x && grep 'write.*child-' /tmp/trace
child-0 (pid 867548) receives: 0
child-1 (pid 867549) receives: 1
child-2 (pid 867550) receives: 2
867548 write(1, "child-0 (pid 867548) receives: 0"..., 33) = 33
867549 write(1, "child-1 (pid 867549) receives: 1"..., 33) = 33
867550 write(1, "child-2 (pid 867550) receives: 2"..., 33) = 33
$ strace -o /tmp/trace -f ./x > out && cat out && grep 'write.*child-' /tmp/trace
child-0 (pid 867515) receives: 0
child-1 (pid 867516) receives: 1
child-2 (pid 867517) receives: 2
child-0 (pid 867515) receives: 0
child-1 (pid 867516) receives: 1
child-0 (pid 867515) receives: 0
867517 write(1, "child-0 (pid 867515) receives: 0"..., 99) = 99
867516 write(1, "child-0 (pid 867515) receives: 0"..., 66) = 66
867515 write(1, "child-0 (pid 867515) receives: 0"..., 33) = 33
可能的解决方案:
另请参阅
this question
。