简体   繁体   English

关闭未使用的管道文件描述符

[英]Closing unused pipe file descriptors

I try to comprehend the basic reason for why closing file descriptors is needed. 我试图理解为什么需要关闭文件描述符的基本原因。 I get the reason for reader side closing write descriptor. 我知道读者端关闭写描述符的原因。 However, conversely, I can't see(simulate) in action the reason for writing side closing read descriptor. 但是,相反地,我无法看到(模拟)编写侧关闭读取描述符的原因。 I try to apply following one, 我尝试以下一项,

When a process tries to write to a pipe for which no process has an open read descriptor, the kernel sends the SIGPIPE signal to the writing process. 当某个进程尝试写入没有进程具有打开的读取描述符的管道时,内核会将SIGPIPE信号发送到写入进程。 By default, this signal kills a process. 默认情况下,此信号会终止进程。

Source, The Linux programming interface, Michael Kerrisk 来源,Linux编程接口,Michael Kerrisk

write() , on error, -1 is returned, and errno is set appropriately. 错误时返回write() ,返回-1 ,并正确设置errno。 EPIPE fd is connected to a pipe or socket whose reading end is closed. EPIPE fd连接到读数端关闭的管道或插座。 When this happens the writing process will also receive a SIGPIPE signal. 发生这种情况时,写入过程还将收到SIGPIPE信号。 (Thus, the write return value is seen only if the program catches, blocks or ignores this signal.) (因此,仅当程序捕获,阻止或忽略此信号时,才能看到写返回值。)

Source, man pages. 来源,手册页。

To do that, I close already read descriptor before fork() . 为此,我在fork()之前关闭已读取的描述符。 Nevertheless, neither I can catch SIGPIPE , nor print error of write() by perror() . 但是,我既无法捕获SIGPIPE ,也无法通过perror()打印write()的错误。

#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/param.h>
#include <signal.h>
#define BUFSIZE 100

char const * errMsgPipe = "signal handled SIGPIPE\n";
int errMsgPipeLen;

void handler(int x) {
    write(2, errMsgPipe, errMsgPipeLen);
}

int main(void) {
    errMsgPipeLen = strlen(errMsgPipe);
    char bufin[BUFSIZE] = "empty";
    char bufout[] = "hello soner";
    int bytesin;
    pid_t childpid;
    int fd[2];

    struct sigaction sa;
    memset(&sa, 0, sizeof(sa));
    sa.sa_flags = 0;
    sigfillset(&sa.sa_mask);
    sa.sa_handler = handler;
    sigaction(SIGPIPE, &sa, 0);

    if (pipe(fd) == -1) {
        perror("Failed to create the pipe");
        return 1;
    }
    bytesin = strlen(bufin);
    childpid = fork();
    if (childpid == -1) {
        perror("Failed to fork");
        return 1;
    }

    close(fd[0]);

    if (childpid) {
        if (write(fd[1], bufout, strlen(bufout)+1) < 0) {
            perror("write");
        }
    }
    else
        bytesin = read(fd[0], bufin, BUFSIZE);
    fprintf(stderr, "[%ld]:my bufin is {%.*s}, my bufout is {%s}\n",
            (long)getpid(), bytesin, bufin, bufout);
    return 0;
}

Output: 输出:

[22686]:my bufin is {empty}, my bufout is {hello soner}
[22687]:my bufin is {empty}, my bufout is {hello soner}

Expected output: 预期产量:

[22686]:my bufin is {empty}, my bufout is {hello soner}
signal handled SIGPIPE or similar stuff

Independent demonstration of why closing read end of a pipe matters 独立演示为何关闭管道的读取端很重要

Here is a scenario where closing the read end of a pipe matters: 在以下情况下,关闭管道的读取端很重要:

seq 65536 | sed 10q

If the process that launches seq does not close the read end of the pipe, then seq will fill the pipe buffer (it would like to write 382,110 bytes, but the pipe buffer isn't that big) but because there is a process with the read end of the pipe open ( seq ), it will not get SIGPIPE or a write error, so it will never complete. 如果启动seq的进程没有关闭管道的读取端,则seq将填充管道缓冲区(它想写入382,110字节,但管道缓冲区不是那么大),但是因为存在一个带有读取管道打开端( seq )的末尾,它将不会获得SIGPIPE或写入错误,因此它将永远不会完成。

Consider this code. 考虑下面的代码。 The program runs seq 65536 | sed 10q 该程序运行seq 65536 | sed 10q seq 65536 | sed 10q , but depending on whether it is invoked with any arguments or not, it does or does not close the read end of the pipe to the seq program. seq 65536 | sed 10q ,但是根据是否使用任何参数调用它,它是否关闭对seq程序的管道的读取端。 When it is run without arguments, the seq program never gets SIGPIPE or a write error on its standard output because there is a process with the read end of the pipe open — that process is seq itself. 如果在不带参数的情况下运行seq程序,则它的标准输出永远不会获得SIGPIPE或写入错误,因为存在一个进程,该进程的管道的读取端处于打开状态–该进程本身就是seq

#include "stderr.h"
#include <stdio.h>
#include <sys/wait.h>
#include <unistd.h>

int main(int argc, char **argv)
{
    err_setarg0(argv[0]);
    int fd[2];
    int pid1;
    int pid2;

    if (pipe(fd) != 0)
        err_syserr("failed to pipe: ");
    if ((pid1 = fork()) < 0)
        err_syserr("failed to fork 1: ");
    else if (pid1 == 0)
    {
        char *sed[] = { "sed", "10q", 0 };
        if (dup2(fd[0], STDIN_FILENO) < 0)
            err_syserr("failed to dup2 read end of pipe to standard input: ");
        close(fd[0]);
        close(fd[1]);
        execvp(sed[0], sed);
        err_syserr("failed to exec %s: ", sed[0]);
    }
    else if ((pid2 = fork()) < 0)
        err_syserr("failed to fork 2: ");
    else if (pid2 == 0)
    {
        char *seq[] = { "seq", "65536", 0 };
        if (dup2(fd[1], STDOUT_FILENO) < 0)
            err_syserr("failed to dup2 write end of pipe to standard output: ");
        close(fd[1]);
        if (argc > 1)
            close(fd[0]);
        execvp(seq[0], seq);
        err_syserr("failed to exec %s: ", seq[0]);
    }
    else
    {
        int corpse;
        int status;
        close(fd[0]);
        close(fd[1]);
        printf("read end of pipe is%s closed for seq\n", (argc > 1) ? "" : " not");
        printf("shell process is PID %d\n", (int)getpid());
        printf("sed launched as PID %d\n", pid1);
        printf("seq launched as PID %d\n", pid2);
        while ((corpse = wait(&status)) > 0)
            printf("%d exited with status 0x%.4X\n", corpse, status);
        printf("shell process is exiting\n");
    }
}

The library code is available in my SOQ (Stack Overflow Questions) repository on GitHub as files stderr.c and stderr.h in the src/libsoq sub-directory. 库代码在GitHub上的我的SOQ (堆栈溢出问题)存储库中以src / libsoq子目录中的stderr.cstderr.h文件的stderr.c

Here's a pair of sample runs (the program was called fork29 ): 这是一对示例运行(该程序称为fork29 ):

$ fork29
read end of pipe is not closed for seq
shell process is PID 90937
sed launched as PID 90938
seq launched as PID 90939
1
2
3
4
5
6
7
8
9
10
90938 exited with status 0x0000
^C
$ fork29 close
read end of pipe is closed for seq
shell process is PID 90940
sed launched as PID 90941
seq launched as PID 90942
1
2
3
4
5
6
7
8
9
10
90941 exited with status 0x0000
90942 exited with status 0x000D
shell process is exiting
$

Note that the exit status of seq in the second example indicates that it died from signal 13, SIGPIPE. 请注意,第二个示例中seq的退出状态表明它已死于信号13 SIGPIPE。

Question about the solution above 有关上述解决方案的问题

(1) How are we sure that here seq executes before sed ? (1)我们如何确定seqsed之前执行? How is there no race? 怎么没有种族?

The two programs ( seq and sed ) execute concurrently. 这两个程序( seqsed )同时执行。 sed cannot read anything until seq has produced it. seq生成之前, sed无法读取任何内容。 seq might fill the pipe before sed reads anything, or it might only fill it after sed has quit. seq可能在sed读取任何内容之前就填充了管道,或者可能仅在sed退出之后才填充了管道。

(2) Why do we close both fd[0] and fd[1] in sed ? (2)为什么在sed同时关闭fd[0]fd[1] Why not only fd[1] ? 为什么不仅是fd[1] Similar for seq . seq类似。

Rule of thumb : If you dup2() one end of a pipe to standard input or standard output, close both of the original file descriptors returned by pipe() as soon as possible. 经验法则 :如果将管道的一端dup2()为标准输入或标准输出,请尽快关闭pipe()返回的两个原始文件描述符。 In particular, you should close them before using any of the exec*() family of functions. 特别是,在使用任何exec*()系列函数之前,应关闭它们。

The rule also applies if you duplicate the descriptors with either dup() or fcntl() with F_DUPFD 如果您使用带有F_DUPFD dup()fcntl()复制描述符,则该规则也适用

The code for sed follows the Rule of Thumb. sed的代码遵循经验法则。 The code for seq only does so conditionally, so you can see what happens when you don't follow the Rule of Thumb. seq的代码仅在有条件的情况下执行,因此您可以看到不遵循经验法则时会发生什么。

Independent demonstration of why closing write end of a pipe matters 独立演示为何关闭管道的写入结束很重要

Here is a scenario where closing the write end of a pipe matters: 在以下情况下,关闭管道的写端很重要:

ls -l | sort

If the process that launches sort does not close the write end of the pipe, then sort could write to the pipe, so it will never see EOF on the pipe, so it will never complete. 如果启动sort的进程没有关闭管道的写入端,则sort可能会写入管道,因此它将永远不会在管道上看到EOF,因此它将永远不会完成。

Consider this code. 考虑下面的代码。 The program runs ls -l | sort 该程序运行ls -l | sort ls -l | sort , but depending on whether it is invoked with any arguments or not, it does or does not close the write end of the pipe to the sort program. ls -l | sort ,但是取决于是否使用任何参数调用它,它是否关闭对sort程序的管道的写端。 When it is run without arguments, then, the sort program never sees EOF on its standard input because there is a process with the write end of the pipe open — that process is sort itself. 当它不带参数运行时, sort程序就永远不会在其标准输入上看到EOF,因为有一个进程的管道的写端处于打开状态–该进程本身就是sort

#include "stderr.h"
#include <stdio.h>
#include <sys/wait.h>
#include <unistd.h>

int main(int argc, char **argv)
{
    err_setarg0(argv[0]);
    int fd[2];
    int pid1;
    int pid2;

    if (pipe(fd) != 0)
        err_syserr("failed to pipe: ");
    if ((pid1 = fork()) < 0)
        err_syserr("failed to fork 1: ");
    else if (pid1 == 0)
    {
        char *sort[] = { "sort", 0 };
        if (dup2(fd[0], STDIN_FILENO) < 0)
            err_syserr("failed to dup2 read end of pipe to standard input: ");
        close(fd[0]);
        if (argc > 1)
            close(fd[1]);
        execvp(sort[0], sort);
        err_syserr("failed to exec %s: ", sort[0]);
    }
    else if ((pid2 = fork()) < 0)
        err_syserr("failed to fork 2: ");
    else if (pid2 == 0)
    {
        char *ls[] = { "ls", "-l", 0 };
        if (dup2(fd[1], STDOUT_FILENO) < 0)
            err_syserr("failed to dup2 write end of pipe to standard output: ");
        close(fd[1]);
        close(fd[0]);
        execvp(ls[0], ls);
        err_syserr("failed to exec %s: ", ls[0]);
    }
    else
    {
        int corpse;
        int status;
        close(fd[0]);
        close(fd[1]);
        printf("write end of pipe is%s closed for sort\n", (argc > 1) ? "" : " not");
        printf("shell process is PID %d\n", (int)getpid());
        printf("sort launched as PID %d\n", pid1);
        printf("ls   launched as PID %d\n", pid2);
        while ((corpse = wait(&status)) > 0)
            printf("%d exited with status 0x%.4X\n", corpse, status);
        printf("shell process is exiting\n");
    }
}

Here's a pair of sample runs (the program was called fork13 ): 这是一对示例运行(该程序称为fork13 ):

$ fork13
write end of pipe is not closed for sort
shell process is PID 90737
sort launched as PID 90738
ls   launched as PID 90739
90739 exited with status 0x0000
^C
$ fork13 close
write end of pipe is closed for sort
shell process is PID 90741
sort launched as PID 90742
ls   launched as PID 90743
90743 exited with status 0x0000
-rw-r--r--  1 jleffler  staff   1583 Jun 23 14:20 fork13.c
-rwxr-xr-x  1 jleffler  staff  22216 Jun 23 14:20 fork13
drwxr-xr-x  3 jleffler  staff     96 Jun 23 14:06 fork13.dSYM
total 56
90742 exited with status 0x0000
shell process is exiting
$

(3) Why do we need to close both fd[0] and fd[1] in their parent? (3)为什么我们需要同时关闭它们的父级中的fd[0]fd[1]

The parent process isn't actively using the pipe it created. 父进程未积极使用其创建的管道。 It must close it fully, otherwise the other programs won't end. 它必须完全关闭它,否则其他程序将不会结束。 Try it — I did (unintentionally) and the programs didn't behave as I intended (expected). 尝试一下-我(无意间)做了,并且程序没有达到我的预期(预期)。 It took me a couple of seconds to realize what I'd not done! 我花了几秒钟才意识到我还没做完!

Adaptation of code from answer by OP 通过OP改编代码

snr posted an 'answer' attempting to demonstrate signal handling and what happens with closing (or not) the read end of pipe file descriptors. snr发布了一个“答案”,试图演示信号处理以及关闭(或不关闭)管道文件描述符的读取端时发生的情况。 Here's an adaptation of that code into a program that can be controlled with command line options, where permutations of the options can yield different and useful results. 这是将该代码改编为可以通过命令行选项控制的程序,其中选项的排列可以产生不同且有用的结果。 The -b and -a options allow you to close the read end of the pipe before or after the fork (or not close it at all). -b-a选项允许您在派生叉之前或之后关闭管道的读取端(或完全不关闭)。 The -h and -i allow you to handle SIGPIPE with the signal handler or ignore it (or use the default handling — terminate). -h-i允许您使用信号处理程序来处理SIGPIPE或将其忽略(或使用默认处理-终止)。 And the -d option allows you to delay the parent by 1 second before it attempts to write. -d选项使您可以在父级尝试写入之前将其延迟1秒。

#include <errno.h>
#include <signal.h>
#include <stdbool.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include "stderr.h"

#define BUFSIZE 100

static char const *errMsgPipe = "signal handled SIGPIPE\n";
static int errMsgPipeLen;

static void handler(int x)
{
    if (x == SIGPIPE)
        write(2, errMsgPipe, errMsgPipeLen);
}

static inline void print_bool(const char *tag, bool value)
{
    printf("  %5s: %s\n", (value) ? "true" : "false", tag);
}

int main(int argc, char **argv)
{
    err_setarg0(argv[0]);

    bool sig_ignore = false;
    bool sig_handle = false;
    bool after_fork = false;
    bool before_fork = false;
    bool parent_doze = false;
    static const char usestr[] = "[-abdhi]";

    int opt;
    while ((opt = getopt(argc, argv, "abdhi")) != -1)
    {
        switch (opt)
        {
        case 'a':
            after_fork = true;
            break;
        case 'b':
            before_fork = true;
            break;
        case 'd':
            parent_doze = true;
            break;
        case 'h':
            sig_handle = true;
            break;
        case 'i':
            sig_ignore = true;
            break;
        default:
            err_usage(usestr);
        }
    }

    if (optind != argc)
        err_usage(usestr);

    /* Both these happen naturally - but should be explicit when printing configuration */
    if (sig_handle && sig_ignore)
        sig_ignore = false;
    if (before_fork && after_fork)
        after_fork = false;

    printf("Configuration:\n");
    print_bool("Close read fd before fork", before_fork);
    print_bool("Close read fd after  fork", after_fork);
    print_bool("SIGPIPE handled", sig_handle);
    print_bool("SIGPIPE ignored", sig_ignore); 
    print_bool("Parent doze", parent_doze);

    err_setlogopts(ERR_PID);

    errMsgPipeLen = strlen(errMsgPipe);
    char bufin[BUFSIZE] = "empty";
    char bufout[] = "hello soner";
    int bytesin;
    pid_t childpid;
    int fd[2];

    struct sigaction sa;
    memset(&sa, 0, sizeof(sa));
    sa.sa_flags = 0;
    sigfillset(&sa.sa_mask);
    sa.sa_handler = SIG_DFL;
    if (sig_ignore)
        sa.sa_handler = SIG_IGN;
    if (sig_handle)
        sa.sa_handler = handler;
    if (sigaction(SIGPIPE, &sa, 0) != 0)
        err_syserr("sigaction(SIGPIPE) failed: ");

    printf("Parent: %d\n", (int)getpid());

    if (pipe(fd) == -1)
        err_syserr("pipe failed: ");

    if (before_fork)
        close(fd[0]);

    int val = -999;
    bytesin = strlen(bufin);
    childpid = fork();
    if (childpid == -1)
        err_syserr("fork failed: ");

    if (after_fork)
        close(fd[0]);

    if (childpid)
    {
        if (parent_doze)
            sleep(1);
        val = write(fd[1], bufout, strlen(bufout) + 1);
        if (val < 0)
            err_syserr("write to pipe failed: ");
        err_remark("Parent wrote %d bytes to pipe\n", val);
    }
    else
    {
        bytesin = read(fd[0], bufin, BUFSIZE);
        if (bytesin < 0)
            err_syserr("read from pipe failed: ");
        err_remark("Child read %d bytes from pipe\n", bytesin);
    }

    fprintf(stderr, "[%ld]:my bufin is {%.*s}, my bufout is {%s}\n",
            (long)getpid(), bytesin, bufin, bufout);

    return 0;
}

It can be difficult (non-obvious, at any rate) to track what happens to the parent process. 跟踪父进程发生的事情可能很困难(很明显)。 Bash generates an exit status of 128 + signal number when a child dies from a signal. 当孩子从信号中死亡时,Bash会生成退出状态128 +信号编号。 On this machine, SIGPIPE is 13, so an exit status of 141 indicates death from SIGPIPE. 在这台机器上,SIGPIPE为13,因此退出状态为141表示已从SIGPIPE中退出。

Example runs: 示例运行:

$ pipe71; echo $?
Configuration:
  false: Close read fd before fork
  false: Close read fd after  fork
  false: SIGPIPE handled
  false: SIGPIPE ignored
  false: Parent doze
Parent: 97984
pipe71: pid=97984: Parent wrote 12 bytes to pipe
[97984]:my bufin is {empty}, my bufout is {hello soner}
pipe71: pid=97985: Child read 12 bytes from pipe
[97985]:my bufin is {hello soner}, my bufout is {hello soner}
0
$ pipe71 -b; echo $?
Configuration:
   true: Close read fd before fork
  false: Close read fd after  fork
  false: SIGPIPE handled
  false: SIGPIPE ignored
  false: Parent doze
Parent: 97987
pipe71: pid=97988: read from pipe failed: error (9) Bad file descriptor
141
$ pipe71 -a; echo $?
Configuration:
  false: Close read fd before fork
   true: Close read fd after  fork
  false: SIGPIPE handled
  false: SIGPIPE ignored
  false: Parent doze
Parent: 98000
pipe71: pid=98000: Parent wrote 12 bytes to pipe
[98000]:my bufin is {empty}, my bufout is {hello soner}
0
pipe71: pid=98001: read from pipe failed: error (9) Bad file descriptor
$ pipe71 -a -d; echo $?
Configuration:
  false: Close read fd before fork
   true: Close read fd after  fork
  false: SIGPIPE handled
  false: SIGPIPE ignored
   true: Parent doze
Parent: 98004
pipe71: pid=98005: read from pipe failed: error (9) Bad file descriptor
141
$ pipe71 -h -a -d; echo $?
Configuration:
  false: Close read fd before fork
   true: Close read fd after  fork
   true: SIGPIPE handled
  false: SIGPIPE ignored
   true: Parent doze
Parent: 98007
pipe71: pid=98008: read from pipe failed: error (9) Bad file descriptor
signal handled SIGPIPE
pipe71: pid=98007: write to pipe failed: error (32) Broken pipe
1
$ pipe71 -h -a; echo $?
Configuration:
  false: Close read fd before fork
   true: Close read fd after  fork
   true: SIGPIPE handled
  false: SIGPIPE ignored
  false: Parent doze
Parent: 98009
pipe71: pid=98009: Parent wrote 12 bytes to pipe
[98009]:my bufin is {empty}, my bufout is {hello soner}
pipe71: pid=98010: read from pipe failed: error (9) Bad file descriptor
0
$ pipe71 -i -a; echo $?
Configuration:
  false: Close read fd before fork
   true: Close read fd after  fork
  false: SIGPIPE handled
   true: SIGPIPE ignored
  false: Parent doze
Parent: 98013
pipe71: pid=98013: Parent wrote 12 bytes to pipe
[98013]:my bufin is {empty}, my bufout is {hello soner}
0
pipe71: pid=98014: read from pipe failed: error (9) Bad file descriptor
$ pipe71 -d -i -a; echo $?
Configuration:
  false: Close read fd before fork
   true: Close read fd after  fork
  false: SIGPIPE handled
   true: SIGPIPE ignored
   true: Parent doze
Parent: 98015
pipe71: pid=98016: read from pipe failed: error (9) Bad file descriptor
pipe71: pid=98015: write to pipe failed: error (32) Broken pipe
1
$ pipe71 -i -a; echo $?
Configuration:
  false: Close read fd before fork
   true: Close read fd after  fork
  false: SIGPIPE handled
   true: SIGPIPE ignored
  false: Parent doze
Parent: 98020
pipe71: pid=98020: Parent wrote 12 bytes to pipe
[98020]:my bufin is {empty}, my bufout is {hello soner}
0
pipe71: pid=98021: read from pipe failed: error (9) Bad file descriptor
$

On my machine (a MacBook Pro running macOS High Sierra 10.13.5, with GCC 8.1.0), if I do not delay the parent, the parent consistently writes to the pipe before the child gets around to closing the file descriptor. 在我的机器上(运行macOS High Sierra 10.13.5且运行GCC 8.1.0的MacBook Pro),如果我不延迟父级,则父级会在子级关闭文件描述符之前始终写入管道。 That is not, however, guaranteed behaviour. 但是,这不能保证行为。 It would be possible to add another option (eg -n for child_nap ) to make the child nap for a second. 可以添加另一个选项(例如, -n表示child_nap )以使子级小睡一秒钟。

Code is available on GitHub 代码在GitHub上可用

The code for the programs shown above ( fork29.c , fork13.c , pipe71.c ) are available in my SOQ (Stack Overflow Questions) repository on GitHub as files fork13.c , fork29.c , pipe71.c in the src/so-5100-4470 sub-directory. 上面显示的程序代码( fork29.cfork13.cpipe71.c )在GitHub上的我的SOQ (堆栈溢出问题)存储库中以src /中的fork13.cfork29.cpipe71.c文件fork13.cso-5100-4470子目录。

My problem is related to place of close(fd[0]); 我的问题与close(fd[0]);位置有关close(fd[0]); I comment out its reason in the code. 我在代码中注释掉了它的原因。 Now, I get the error expected. 现在,我得到了预期的错误。

#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/param.h>
#include <signal.h>
#include <errno.h>
#define BUFSIZE 100

char const * errMsgPipe = "signal handled SIGPIPE\n";
int errMsgPipeLen;

void handler(int x) {
    write(2, errMsgPipe, errMsgPipeLen);
}

int main(void) {
    errMsgPipeLen = strlen(errMsgPipe);
    char bufin[BUFSIZE] = "empty";
    char bufout[] = "hello soner";
    int bytesin;
    pid_t childpid;
    int fd[2];

    struct sigaction sa;
    memset(&sa, 0, sizeof(sa));
    sa.sa_flags = 0;
    sigfillset(&sa.sa_mask);
    sa.sa_handler = handler;
    sigaction(SIGPIPE, &sa, 0);

    if (pipe(fd) == -1) {
        perror("Failed to create the pipe");
        return 1;
    }

    close(fd[0]); // <-- it's in order for no process has an open read descriptor


    int val = -999;
    bytesin = strlen(bufin);
    childpid = fork();
    if (childpid == -1) {
        perror("Failed to fork");
        return 1;
    }


/*
 * close(fd[0]); <---- if it were here, we wouldn't get expected error and signal
 *                      since, parent can be reached to write(fd[1], .... ) call
 *                      before the child close(fd[0]); call defined here it. 
 *          It means there is by child open read descriptor seen by parent.
 */

// sleep(1);     <---- we can prove my saying by calling sleep() here



    if (childpid) {

       val = write(fd[1], bufout, strlen(bufout)+1);
       if (val < 0) {
           perror("writing process error");
       }

    }
    else {
        bytesin = read(fd[0], bufin, BUFSIZE);
    }
    fprintf(stderr, "[%ld]:my bufin is {%.*s}, my bufout is {%s}\n",
            (long)getpid(), bytesin, bufin, bufout);
    return 0;
}

Output: 输出:

signal handled SIGPIPE
writing process error: Broken pipe
[27289]:my bufin is {empty}, my bufout is {hello soner}
[27290]:my bufin is {empty}, my bufout is {hello soner}

Therewithal, the saying that if the parent's write operation fails, the child's bufin contains empty is verified. 因此,可以说, 如果父母的写操作失败,则孩子的bufin包含empty

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

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