C 父级过早终止时的子级反转输出
这是我试图实现的一些伪代码: 叉子 在子级中,将输出描述符复制到文件,然后执行不同的程序 在parent中,在一段时间后杀死孩子C 父级过早终止时的子级反转输出,c,unix,exec,fork,signals,C,Unix,Exec,Fork,Signals,这是我试图实现的一些伪代码: 叉子 在子级中,将输出描述符复制到文件,然后执行不同的程序 在parent中,在一段时间后杀死孩子 问题是,在我杀死子文件后,输出文件是空的,即使子文件在某个阶段写入了它。我做错了什么?我不想等待孩子,但我也不想让它反转已经写入文件的内容。如果你的孩子因信号而死亡,它将不会刷新任何缓冲区,这就是你看不到任何输出的原因。这是有解决办法的 处理信号并刷新缓冲区 使用无缓冲I/O(应避免此情况) 同步子对象和父对象(使用管道)(以便父对象知道杀死子对象是安全的) 当然
问题是,在我杀死子文件后,输出文件是空的,即使子文件在某个阶段写入了它。我做错了什么?我不想等待孩子,但我也不想让它反转已经写入文件的内容。如果你的孩子因信号而死亡,它将不会刷新任何缓冲区,这就是你看不到任何输出的原因。这是有解决办法的
- 处理信号并刷新缓冲区
- 使用无缓冲I/O(应避免此情况)
- 同步子对象和父对象(使用管道)(以便父对象知道杀死子对象是安全的)
stdio
(printf、fwrite等),出于I/O效率的考虑,使用了一些缓冲区。也就是说,当您执行一个简单的写操作时,低级操作不会立即发生。数据被复制到某个缓冲区,之后,当库认为有必要时(满缓冲区或其他东西),缓冲区将被刷新—将写入内容
现在,当程序调用exit(3)
(正常进程终止)时,发生的事情之一是stdio
缓冲区被刷新。如果一个程序由于一个信号而死机,stdio
缓冲区不会被刷新,内存只会被操作系统占用
如果你不能控制你执行的程序(比如说你是一个shell),你就不能确定如果你杀死它们,它们会做什么。也就是说,这不是你的责任。然而,如果你确实控制了它们(你说了一些关于管道的事情),你可以简单地通过管道发出信号,让孩子们调用
exit(3)
,kill
做你想做的事情(将SIGINT
发送到childpid
)。你到底有什么问题?哦,好的。我将文件描述符复制到一个文件中,以便我的子进程写入,然后在子进程中执行。这是可行的,但我的问题是,一旦我杀死了这个孩子,输出文件就会变成空的。如果我不杀死它,那么它从我的子进程中有正确的输出,但是如果我杀死它,那么它就什么都没有了(即使在我杀死它之前它已经将内容写入文件)。在我杀死输出流之前,我需要告诉孩子关闭输出流吗?请编辑你的问题(以及它的标题),以准确地解释正在发生的事情以及你想要发生的事情。如果你需要孩子完成某件事,不等待他正确完成是没有意义的。我不想等他完成,但我也不想让他逆转已经完成的事情(写入文件),所以我不明白他在做什么。我会编辑这个问题。谢谢!如果我不想更改正在执行的程序,我想做以下哪一项?@Sam嗯,既然你不想修改你执行的程序,很难说。为什么不让它正常退出呢?如果它不应该正常退出,你怎么知道什么时候该杀了它?我需要用户能够向它发送信号来杀了它,但我不想让它擦除它已经做过的事情。老实说,我真的不明白为什么它会抹去它已经做过的事情。你能解释一下关于刷新缓冲区的更多信息吗?为什么这是必要的?我能在父母身上做吗?你为什么说孩子“正在抹去已经做过的事情”?如果事实上您看到文件中的数据在孩子被杀死时被截断,那将是非常了不起的。在你杀死孩子之前,你怎么知道他做了什么呢?@Sam:正确的方法不是sleep(1)
,而是先用sigprogmask
阻止SIGCHLD
,然后发送SIGINT
,使用sigtimedwait
等待SIGCHLD
,使用waitpid
和WNOHANG
查看它是否已退出,如果未退出,则发送SIGKILL
。这样你就避免了在你的程序中引入不必要的延迟——用户肯定讨厌这种延迟!