fclose()ing其文件描述符块,直到子进程结束(大概是因为流已经结束)后调用dup()这里。

FILE *f = popen("./output", "r");
int d = dup(fileno(f));
fclose(f);

然而,通过手动执行pipe()fork(),所述execvp()popen(),然后dup()ing管道的读文件描述符,关闭原始不会阻塞。

int p[2];
pipe(p);
switch (fork()) {
    case 0: {
        char *argv[] = {"./output", NULL};
        close(p[0]);
        dup2(p[1], 1);
        execvp(*argv, argv);
    }
    default: {
        close(p[1]);
        int d = dup(p[0]);
        close(p[0]);
    }
}

为什么会发生这种情况,我怎么能关闭FILE *popen()返回,并在其位置使用文件描述符?

<强>更新

我知道,文件说,使用pclose(),但是fclose()块为好。此外,我在glibc的代码戳左右,而pclose()只是调用fclose()。的行为是相同的,或fclose()是否pclose()使用。

有帮助吗?

解决方案 2

与所述答案的一般性失望迄今(I可以 RTFM ,tyvm),I “VE彻底调查此,通过步进和读取的glibc 源。

在的glibc pclose()直接调用fclose()没有额外的效果,所以2级的呼叫是一样的。事实上,你可以使用pclose()和互换fclose()。我敢肯定,这是纯粹的演进实施巧合,以及使用pclose()来关闭FILE *返回从popen()仍建议。

在神奇的是在popen()。在glibc的FILE *s包含有指向跳转表到适当的函数来处理此类呼叫的fseek()fread(),和相关fclose()的。当调用popen(),比fopen()使用的人用不同的跳转表。所述close构件在该跳转表指向一个特殊功能_IO_new_proc_close,其上的PID存储在区域调用waitpid()通过FILE *指向。

下面是我的glibc版本,我已经与正在发生的事情上做笔记注释相关的调用堆栈:

// linux waitpid system call interface
#0  0x00f9a422 in __kernel_vsyscall ()
#1  0x00c38513 in __waitpid_nocancel () from /lib/tls/i686/cmov/libc.so.6

// removes fp from a chain of proc files
// and waits for the process of the stored pid to terminate
#2  0x00bff248 in _IO_new_proc_close (fp=0x804b008) at iopopen.c:357

// flushes the stream and calls close in its jump table
#3  0x00c09ff3 in _IO_new_file_close_it (fp=0x804b008) at fileops.c:175

// destroys the FILEs buffers
#4  0x00bfd548 in _IO_new_fclose (fp=0x804b008) at iofclose.c:62

// calls fclose
#5  0x00c017fd in __new_pclose (fp=0x804b008) at pclose.c:43

// calls pclose
#6  0x08048788 in main () at opener.c:34

所以它的短路,使用popen(),返回FILE *不能关闭,即使你dup()它的文件描述符,因为它会阻止,直到子进程终止。当然,在此之后,你会留下一个文件描述符其中将包含一个管不管孩子的过程管理,以write()方法来终止它之前。

如果不从fread()返回的文件指针popen()ing,底层管道不会被触动,它是安全的fileno()使用文件描述符,并通过调用pclose()完成了。

其他提示

http://linux.die.net/man/3/popen

<强>的函数,pclose()函数等待关联的进程终止并返回命令的退出状态通过wait4()返回。

由于pclose函数()要返回退出状态,它必须等待子终止并生成一个。由于FCLOSE()调用函数,pclose(),同样适用于FCLOSE()为您服务。

如果您fork和exec和你自己做休息,你不最终调用函数,pclose()(直接或间接),所以没有在接近的时间等待。但是请注意,除非你的程序设置为忽略SIGCHLD,你的进程将不会终止(而不是它会去僵尸),直到孩子一样。但至少你的成本将运行第一个退出。

通过FILE*返回的popen()应由pclose()被关闭,而不是由fclose()。然后,对于pclose()的说明文件:

  

在pclose函数()函数等待   相关进程终止和   返回命令的退出状态   如通过wait4()返回。

所以等待是的两件事情pclose()确实,除了关闭文件描述符之一。 close()做的只有一件事:它关闭描述符

在回答您的第二个问题,我想你可以使用fileno()返回的描述符。有没有必要dup()它。你用它完成后,pclose()原来的。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top