FCLOSE()/ pclose函数()可能会阻止某些文件指针 [英] fclose()/pclose() may block on some file pointers

查看:1537
本文介绍了FCLOSE()/ pclose函数()可能会阻止某些文件指针的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

调用 FCLOSE()这里经过 DUP() ING的文件描述符块,直到子进程结束( presumably因为流已经结束)。

Calling fclose() here after dup()ing its file descriptor blocks until the child process has ended (presumably because the stream has ended).

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

但是,通过手动执行管道()叉() execvp( )的popen(),然后 DUP() ING管道的读取文件描述,关闭原始不会阻止。

However by manually performing the pipe(), fork(), execvp() of the popen(), and then dup()ing the pipe's read file descriptor, closing the original does not block.

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()返回并使用在其位置文件描述符?

Why does this occur, and how can I close the FILE * returned from popen() and use a file descriptor in its place?

更新:

我知道该文档说,使用函数,pclose(),但 FCLOSE()块以及。此外,我在glibc的code戳左右,而函数,pclose()只是调用 FCLOSE()。该行为是相同的,无论是 FCLOSE()函数,pclose()被使用。

I'm aware that the documentation says to use pclose(), however fclose() blocks as well. Furthermore, I poked around in the glibc code, and pclose() just calls fclose(). The behaviour is the same, whether fclose() or pclose() is used.

推荐答案

到目前为止的答案的一般性失望(我可以 RTFM ,tyvm),我已经调查清楚这一点,通过加强和阅读 glibc的来源。

Disappointed with the generality of the answers so far (I can RTFM, tyvm), I've investigated this thoroughly, by stepping through and reading the glibc source.

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

In glibc pclose() directly calls fclose() with no additional effect, so the 2 calls are same. In fact you could use pclose() and fclose() interchangeably. I'm sure this is purely a coincidence in the evolved implementation, and the use of pclose() to close a FILE * returned from popen() is still recommended.

神奇的是在的popen() FILE * S IN的glibc包含有指向相应的功能来处理这种呼叫跳转表中的 fseek的() FREAD(),和相关的 FCLOSE()。打电话时的popen(),比使用的fopen一个使用不同的跳转表()。在关闭成员在此跳表指向一个特殊的函数 _IO_new_proc_close ,要求 waitpid函数( )存储在该地区的pid指向 FILE *

The magic is in popen(). FILE *s in glibc contain a jump table with pointers to appropriate functions to handle such calls as fseek(), fread(), and of relevance fclose(). When calling popen(), a different jump table used than the one used by fopen(). The close member in this jump table points to a special function _IO_new_proc_close, which calls waitpid() on the pid stored in the region pointed to by FILE *.

下面是我的版本的glibc,我已经约是怎么回事笔记注释相关调用堆栈:

Here's the relevant call stack in my version of glibc, which I've annotated with notes about what is going on:

// 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()的文件描述符,因为它会阻止,直到子进程结束。当然,在此之后,你会留下一个文件描述符其中将包含一个管不管子进程设法写()把它终止了。

So the short of it is, using popen(), the returned FILE * must not be closed, even if you dup() its file descriptor, because it will block until the child process terminates. Of course, after this you'll be left with a file descriptor to a pipe which will contain whatever the child process managed to write() to it before terminating.

由于没有 FREAD()的popen()返回文件指针ING,底层管道不会被触动,它的安全使用由文件描述符的fileno(),并通过调用 pclose函数完成了()

By not fread()ing with the file pointer returned from popen(), the underlying pipe will not be touched, it's safe to use the file descriptor by fileno(), and finish up by calling pclose().

这篇关于FCLOSE()/ pclose函数()可能会阻止某些文件指针的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆