在popen()
的glibc实现中,它指定
popen()函数应确保来自先前popen()调用的所有在父进程中保持打开的流在新的子进程中关闭。
为什么?如果目的是避免fd泄漏,为什么不直接关闭所有打开的fd呢?
popen()
的glibc实现使用fork()
。虽然在fork()
和exec()
之间有dup2()
和close()
调用,但是否有可能用vfork()
代替fork()
以提高性能?
popen()
的Linux实现是基于fork()
而不是vfork()
吗?为什么(或为什么不)?
我将编写一个双向版本的popen()
,它返回两个FILE*
:一个用于读,一个用于写。我如何正确地实现它?它应该是线程安全的,没有fd泄漏。
vfork(2)已经过时了(从POSIX2008中删除),而fork(2)非常高效,因为它使用了写时复制技术。
popen(3)不能关闭所有打开的文件,因为它不知道它们,也不知道哪些是相关的。设想一个程序获取一个socket
,并将其文件描述符作为参数传递给popen
-ed命令(或简单地称为popen("time cat /etc/issue >&9; date","r")
....)。参见fcntl(2) with FD_CLOEXEC
, open(2) with O_CLOEXEC
, execve(2)
文件描述符是程序范围和进程范围的资源,正确管理它们是您的责任。您应该知道在execve
之前子进程中应该关闭哪些fd。如果您知道execve
-d是什么程序以及它需要什么fds,那么您可以在execve
之前close
所有其他fds(或者大多数fds,可能使用for (int i=STDERR_FILENO+1; i<64; i++) (void) close(i);
)。
如果你正在编写一个可重用的库,文档关于文件描述符(以及任何其他全局进程范围的资源)的策略,并且可能在它自己获取的任何文件描述符上使用FD_CLOEXEC
(不是作为显式参数或数据),例如用于内部使用。
它看起来像你在重新发明p2open(那么你可能需要了解你的FILE
在你的C标准库的实现细节,否则使用fdopen(3)小心谨慎);您可能会找到它的一些实现。注意,使用该方法的进程可能需要一些事件循环(例如上面的poll(2)…)来避免潜在的死锁(父进程和子进程在读取时都阻塞)。
您是否考虑使用一些现有的事件循环基础设施(例如libevent, libev, GTK中的glib等....)?
顺便说一句,Linux有几个自由软件实现了它的C标准库。GNU libc是非常常见的,但也有musl-libc和其他几个libc。学习libc的源代码