简体   繁体   English

在执行execlp()之后是否需要关闭管道?

[英]Is closing a pipe necessary when followed by execlp()?

Before stating my question, I have read several related questions on stack overflow, such as pipe & dup functions in UNIX , and several others,but didn't clarify my confusion. 在陈述我的问题之前,我已经阅读了一些有关堆栈溢出的相关问题,例如UNIX中的pipe&dup函数以及其他一些问题,但是并没有弄清我的困惑。

First, the code, which is an example code from 'Beginning Linux Programming', 4th edition, Chapter 13: 首先,该代码是“ Beginning Linux Programming”(第4版)第13章中的示例代码:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

int main()
{
int data_processed;
int file_pipes[2];
const char some_data[] = "123";
pid_t fork_result;

if (pipe(file_pipes) == 0)
   {
    fork_result = fork();
    if (fork_result == (pid_t)-1)
       {
        fprintf(stderr, "Fork failure");
        exit(EXIT_FAILURE);
       }

    if (fork_result == (pid_t)0)  // Child process
       {
        close(0);
        dup(file_pipes[0]);
        close(file_pipes[0]);   // LINE A
        close(file_pipes[1]);   // LINE B

        execlp("od", "od", "-c", (char *)0);
        exit(EXIT_FAILURE);
       }
    else    // parent process
       {
        close(file_pipes[0]);   // LINE C
        data_processed = write(file_pipes[1], some_data,
                               strlen(some_data));
        close(file_pipes[1]);   // LINE D
        printf("%d - wrote %d bytes\n", (int)getpid(), data_processed);
       }
   }
exit(EXIT_SUCCESS);
}

The execution result is: 执行结果为:

momo@xue5:~/TestCode/IPC_Pipe$ ./a.out momo @ xue5:〜/ TestCode / IPC_Pipe $ ./a.out

10187 - wrote 3 bytes 10187-写了3个字节

momo@xue5:~/TestCode/IPC_Pipe$ 0000000 1 2 3 momo @ xue5:〜/ TestCode / IPC_Pipe $ 0000000 1 2 3

0000003 0000003

momo@xue5:~/TestCode/IPC_Pipe$ momo @ xue5:〜/ TestCode / IPC_Pipe $

If you commented LINE A, LINE C, and LINE D , the result is the same as above. 如果您评论LINE A,LINE C和LINE D ,则结果与上面相同。 I understand the result, the child get the data from its parent through its own stdin which is connected to pipe, and send 'od -c' result to its stdout. 我了解结果,子级通过连接到管道的自己的stdin从其父级获取数据,并将“ od -c”结果发送到其stdout。

However, if you commented LINE B , the result would be: 但是,如果您评论LINE B ,结果将是:

momo@xue5:~/TestCode/IPC_Pipe$ ./a.out momo @ xue5:〜/ TestCode / IPC_Pipe $ ./a.out

10436 - wrote 3 bytes 10436-写了3个字节

momo@xue5:~/TestCode/IPC_Pipe$ momo @ xue5:〜/ TestCode / IPC_Pipe $

No 'od -c' result! 没有“ od -c”结果! Is 'od -c' started by execlp() not excuted, or its output not directed to stdout? 由execlp()启动的'od -c'是否被执行,或者其输出未定向到stdout? One possibility is the read() of 'od' is blocked, because the write file descriptor file_pipes[1] of child is open if you commented LINE B. But commenting LINE D, which let write file descriptor file_pipes[1] of parent open, can still have the 'od -c' output. 一种可能性是'od'的read()被阻止,因为如果注释了LINE B,则子级的写文件描述符file_pipes [1]是打开的。但是注释了LINE D,这会使父级的写文件描述符file_pipes [1]打开,仍然可以有“ od -c”输出。

And, why we need to close pipe before execlp()? 而且,为什么我们需要在execlp()之前关闭管道? execlp() will replace the process image, including stack, .data, .heap, .text with new image from 'od'. execlp()将用“ od”中的新映像替换过程映像,包括堆栈,.data,.heap,.text。 Does that mean, even if you don't close file_pipes[0] and file_pipes[1] in child as LINE A and B, file_pipes[0] and file_pipes[1] will still be 'destroyed' by execlp()? 这是否意味着,即使您没有像LINE A和B那样关闭子级中的file_pipes [0]和file_pipes [1],execlp()仍会“破坏” file_pipes [0]和file_pipes [1]? From the result by code, it is not. 从代码结果来看,事实并非如此。 But where am I wrong? 但是我哪里错了?

Thanks so much for your time and efforts here~~ 非常感谢您在此付出的时间和精力~~

Is closing a pipe necessary when followed by execlp()? 在执行execlp()之后是否需要关闭管道?

It's not strictly necessary because it depends on how the pipe is used. 并非严格必要,因为这取决于管道的使用方式。 But in general, yes it should be closed if the pipe end is not needed by the process. 但是总的来说,如果过程不需要pipe末端,则应将其关闭。

why we need to close pipe before execlp()? 为什么我们需要在execlp()之前关闭管道? execlp() will replace the process image execlp()将替换过程映像

Because file descriptors (by default) remain open across exec calls. 因为文件描述符(默认情况下)在exec调用之间保持打开状态。 From the man page : "By default, file descriptors remain open across an execve(). File descriptors that are marked close-on-exec are closed; see the description of FD_CLOEXEC in fcntl(2)." 手册页中 :“默认情况下,文件描述符在execve()中保持打开状态。标记为close-on-exec的文件描述符已关闭;请参见fcntl(2)中FD_CLOEXEC的描述。”

However, if you commented LINE B,...No 'od -c' result! 但是,如果您评论LINE B,...没有'od -c'结果!

This is because the od process reads from stdin until it gets an EOF . 这是因为od进程从stdin读取直到获得EOF为止。 If the process itself does not close file_pipes[1] then it will not see an EOF as the write end of the pipe would not be fully closed by all processes that had it opened. 如果进程本身没有关闭file_pipes[1]那么它将不会看到EOF因为打开该管道的所有进程都不会完全关闭该管道的写端。

If you commented LINE A, LINE C, and LINE D, he result is the same as above 如果您评论LINE A,LINE C和LINE D,他的结果与上述相同

This is because the file descriptors at A and C are read ends of the pipe and no one will be blocked waiting for it to be closed (as described above). 这是因为位于A和C的文件描述符是管道的读取端,并且没有人将被阻止等待它被关闭(如上所述)。 The file descriptor at D is a write end and not closing it would indeed cause problems. D处的文件描述符是写端,不关闭它确实会引起问题。 However, even though the code does not explicitly call close on that file descriptor, it will still be closed because the process exits. 但是,即使代码没有显式地调用该文件描述符上的close ,它仍然会因为进程退出而被关闭。

And, why we need to close pipe before execlp()? 而且,为什么我们需要在execlp()之前关闭管道? execlp() will replace the process image, including stack, .data, .heap, .text with new image from 'od'. execlp()将用“ od”中的新映像替换过程映像,包括堆栈,.data,.heap,.text。

Yes, the exec-family functions, including execlp() , replace the process image of the calling process with a copy of the specified program. 是的,exec-family函数(包括execlp()用指定程序的副本替换了调用过程的过程映像。 But the process's table of open file descriptors is not part of the process image -- it is maintained by the kernel, and it survives the exec. 但是进程的打开文件描述符表不是进程映像的一部分-它由内核维护,并且在执行程序中有效。

Does that mean, even if you don't close file_pipes[0] and file_pipes[1] in child as LINE A and B, file_pipes[0] and file_pipes[1] will still be 'destroyed' by execlp()? 这是否意味着,即使您没有像LINE A和B那样关闭子级中的file_pipes [0]和file_pipes [1],execlp()仍会“破坏” file_pipes [0]和file_pipes [1]?

The variable file_pipes is destroyed by execlp() , but that's just the program's internal storage for the file descriptors. execlp()破坏了file_pipes 变量 ,但这只是程序的内部存储文件描述符的地方。 The descriptors are just integer indexes into a table maintained for the process by the kernel. 描述符只是内核为该进程维护的表中的整数索引。 Losing track of the file descriptor values does not cause the associated files to be closed. 丢失对文件描述符值的跟踪不会导致关联文件被关闭。 In fact, that's a form of resource leakage. 实际上,这是资源泄漏的一种形式。

From the result by code, it is not. 从代码结果来看,事实并非如此。 But where am I wrong? 但是我哪里错了?

As described above. 如上所述。

Additionally, when a process exits, all its open file descriptors are closed, but the underlying open file descript ion in the kernel, to which the file descriptors refer, is closed only when no open file descriptors referring to it remain. 另外,当一个进程退出,其所有打开的文件描述符被关闭,但在内核底层打开文件DESCRIPT 离子 ,到文件描述符是指其中,只有在没有打开的文件描述符指的是它仍然是封闭的。 Additional open file descriptors may be held by other processes, as a result of inheriting them across a fork() . 由于在fork()上继承了它们,因此其他进程可能会保留其他打开的文件描述符。

Now as to the specific question of what happens when the child process does not close file_pipes[1] before execing od , you might get a clue by checking the process list via the ps command. 现在关于当子进程在执行od之前没有关闭file_pipes[1]时发生了什么的特定问题,您可能会通过ps命令检查进程列表来获得线索。 You will see the child od process still running (maybe several, if you have tested several times). 您将看到子od进程仍在运行(如果已测试多次,则可能是几个)。 Why? 为什么?

Well, how does od know when to exit? 好吧, od如何知道什么时候退出? It processes its entire input, so it must exit when it reaches the end of its input(s). 它处理整个输入,因此到达输入末尾时必须退出。 But the end of input on a pipe doesn't mean that no more data is available right now , because more data might later be written to the write end of the pipe. 但是,在管道输入的结束并不意味着没有更多的数据是可用的,现在 ,因为更多的数据以后可能被写入管道的写入结束。 End of input on a pipe happens when the write end is closed . 管道上的输入结束发生在关闭写入端时。 And if the child does not close file_pipes[1] before it execs, then it likely will remain open indefinitely, because after the exec the child doesn't any longer know that it owns it. 而且,如果子级在执行前没有关闭file_pipes[1] ,则它可能会无限期保持打开状态,因为执行后,子级不再知道它拥有它。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM