根据她的解释,在 Linux C 编程中,如果主进程 fork 出去两个子进程 B,C 的话,B 和 C 都会拷贝一份所有打开的 file descriptor 。
那么,假设主进程 fork 出去三个进程 ABC ,其中 AB 用 pipe1 连在一块,BC 用 pipe2 连在一块(三个连在一起,比如说echo blahblahcat | grep cat | wc
)。我发现,就算 C 不用 pipe1 ,它也必须把 pipe1 的写入口关掉。
ChatGPT 进一步解释道,这是因为,Linux kernel 会监视每一个 pipe 的每一个写入口。因为 B 和 C 分属两个子进程,所以它们其实是相当于打开了两个 pipe1 的写入口。以上面那个命令行为例,B 中的grep
通过 pipe1 的读入口读入数据,C 中 pipe1 的写入口一直开着,就导致 kernel 没有发送 EOF ,导致grep
挂机。哪怕 B 把自己的 pipe1 写入口关掉都不行,因为 B 和 C 的 pipe1 写入口是两个拷贝。
我又查了很久的 stackoverflow ,感觉她这个解释还是很有道理的,但是毕竟我没读过源代码,所以也不敢肯定,上来请教一下大家,她说的正确吗?
1
Inn0Vat10n 2023-04-22 12:04:55 +08:00
这纠缠的几小时都是在解释你到底想问什么吗,我是没看懂
|
2
levelworm OP |
3
qwq11 2023-04-22 12:24:36 +08:00 1
https://man7.org/linux/man-pages/man7/pipe.7.html
If all file descriptors referring to the write end of a pipe have been closed, then an attempt to read(2) from the pipe will see end-of-file (read(2) will return 0). If all file descriptors referring to the read end of a pipe have been closed, then a write(2) will cause a SIGPIPE signal to be generated for the calling process. If the calling process is ignoring this signal, then write(2) fails with the error EPIPE. An application that uses pipe(2) and fork(2) should use suitable close(2) calls to close unnecessary duplicate file descriptors; this ensures that end-of-file and SIGPIPE/EPIPE are delivered when appropriate. |
4
pcbl 2023-04-22 12:28:08 +08:00 via Android 5
这种问题千万别问 chatgpt ,它会一本正经的胡说八道,你质疑一下它又会胡编出来另一个
|
5
greensea 2023-04-22 12:35:38 +08:00 2
警惕 GPT 依赖,GPT 对于这种定性的问题很容易一本道。对于定性的问题,最好是自己在这个领域已经有了一定程度的了解,才去问 GPT ,否则很容易被带偏还不自知
|
6
levelworm OP @qwq11 对,这个也看了,但是还是没有理解,后来和 ai 掰扯的时候才意识到是哪里弄错了。
|
7
levelworm OP @greensea 你们说的有道理,我也看过文档,但是还是没完全说服自己。怎么说呢,就是不知道自己哪里不知道。
|
8
fds 2023-04-22 13:40:44 +08:00 1
这我也不知道,不过我建议你简单实践一下,编写个程序,可以根据参数定时关闭 fd ,然后监听 pipe 有没有 EOF 打印日志,把几个程序串起来看看。
|
9
fox0001 2023-04-22 13:50:38 +08:00 via Android 1
纠正 ChatGPT 时,它会先承认“你说得都对”,然后开始编“故事”…
|
10
lbinv2 2023-04-22 14:58:42 +08:00 1
@fox0001 笑死,我问 GPT-4 它是不是 GPT-4 他说他是 GPT-3 ,我否定它,它就说它是 GPT-4 ,又否定它,它又说它是 GPT-3
|
11
Y25tIGxpdmlk 2023-04-22 15:59:24 +08:00 1
@fox0001 #9 他还会很乖的跟你道个歉呢
|
12
yin1999 2023-04-22 17:26:44 +08:00 2
举个简单的例子,比如我现在主进程里面使用 pipe 创建了一个管道,然后将输入端的文件描述符传递给 fork 出来的 A ,并在 A 中重定向输出到 pipe 的输入端,关闭 pipe 的输出端文件描述符。但我没有在主进程中关闭输入端的文件描述符并直接 fork 出了进程 B ,在 B 中重定向 Pipe 的输出端到标准输入,也在这里关闭 pipe 的输入端。那即使 A 退出了,B 中调用 read 也是会阻塞的(读不到 EOF )。因为主进程里面没有关闭输入端的文件描述符。
正确的做法是在 fork 出 A 后在主进程直接关闭输入端的文件描述符,再 fork B ,然后再在主进程中关闭输出端文件描述符。这样能保证输入端和输出端的文件描述符仅由两个 fork 出的子进程持有。 fork 得到的文件描述符可以当作引用吧,如果不是所有的引用都断开了,并不会关闭所指向的文件描述符。(不确定是否完全正确,这两天有踩过没在主进程关闭文件描述符的坑) |
13
aijam 2023-04-22 18:19:38 +08:00 1
不就是保证一个 pipe 只有一个 reader 一个 writer 吗?
|
14
veike 2023-04-22 19:52:16 +08:00 1
有些地方 chatgpt 不可靠,我问他休眠会切断电源吗?它回答不会,我说你回答错了,休眠是会切断电源的。它说不好意思,我把休眠和睡眠搞混了。大部分地方 chatGPT 对我确实有帮助,但是有些地方它也会出错。
|
15
swiftg 2023-04-22 20:49:46 +08:00 1
chatGPT 给的数据太假了,一本正经地胡编乱造错误的甚至不存在的东西,连网址都给你瞎编,让他查个东西,80%的数据都是错的,不是了解的东西的话,很容易就被带偏了
|
16
levelworm OP @fds 谢谢,我就是写了程序看到了效果,但是想弄明白里头的原理,同时看不懂源代码,所以只好问。我是用 ps 看的,能看到哪个 S+
|
17
levelworm OP @fox0001 我觉得编程问题,一个是用英文,一个是和他说好不能瞎扯,我觉得就还好。不过我觉得最可惜的是数据库一直是 21 年九月之前的数据。
|
18
levelworm OP @yin1999 多谢,我的错误在于把 file descriptor 看成了指针,以为 close 一次就够了。其实每个子进程都有一个拷贝。
|
19
gaifanking 2023-04-23 09:37:53 +08:00
只做过父子管道通信的供参考:
pipe(fd); pid = fork(); if (pid == 0){ close(fd[0]); } else { close(fd[1]); } 管道在 fork 后就要关掉不需要的那端 我是看的 bili 上李慧芹老师的课程 https://www.bilibili.com/video/BV18p4y167Md?p=236&vd_source=181accc8aeebc9d0f443b049b00fe228 |