为什么写入关闭管道会返回成功

问题描述 投票:0回答:1

我最近读了一篇帖子。在这篇文章中,Soner关闭了父进程和子进程的管道读取端。但是当写入管道时,似乎没有生成 SIGPIPE 信号。

我修改了代码,以确保管道的读取端确实关闭并且write调用返回没有任何错误。

这是我的代码

#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.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) {
        int ret = write(fd[1], bufout, strlen(bufout)+1);
        if (ret < 0) {
            perror("write");
        } else {
                printf("write success, ret: %d\n", ret );
        }
        wait(NULL);
    }
    else{
        bytesin = read(fd[0], bufin, BUFSIZE);
        if(bytesin == -1) {
                perror("child: read");
        }
    }
    fprintf(stderr, "[%ld]:my bufin is {%.*s}, my bufout is {%s}\n",
            (long)getpid(), bytesin, bufin, bufout);
    return 0;
}

输出:

write success, ret: 12
child: read: Bad file descriptor
[9168]:my bufin is {empty}, my bufout is {hello soner}
[9167]:my bufin is {empty}, my bufout is {hello soner}

我修改了代码如下:

#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/param.h>
#include <signal.h>
#include <fcntl.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]);
    bytesin = strlen(bufin);
    childpid = fork();
    if (childpid == -1) {
        perror("Failed to fork");
        return 1;
    }


    if (childpid) {
        int flag = fcntl(fd[0], F_GETFD);
        if(flag = -1) {
                printf("pid:[%d], fcntl: %s\n", getpid(), strerror(errno));
        } else {
                printf("pip: [%d], fd[0] is not closed\n");
        }
        if (write(fd[1], bufout, strlen(bufout)+1) < 0) {
            perror("write");
        }
        //
    }
    else{
        int flag = fcntl(fd[0], F_GETFD);
        if(flag = -1) {
                printf("pid:[%d], fcntl: %s\n", getpid(), strerror(errno));
        } else {
                printf("pip: [%d], fd[0] is not closed\n");
        }
        bytesin = read(fd[0], bufin, BUFSIZE);
        if(bytesin == -1) {
                perror("read");
        }
    }
    fprintf(stderr, "[%ld]:my bufin is {%.*s}, my bufout is {%s}\n",
            (long)getpid(), bytesin, bufin, bufout);
    return 0;
}

但是当我多次运行该程序时,它会产生不同的结果。 例如:

pid:[9200], fcntl: Bad file descriptor
signal handled SIGPIPE
write: Broken pipe
pid:[9201], fcntl: Bad file descriptor
[9200]:my bufin is {empty}, my bufout is {hello soner}
read: Bad file descriptor
[9201]:my bufin is {empty}, my bufout is {hello soner}

另一个结果:

pid:[9189], fcntl: Bad file descriptor
[9189]:my bufin is {empty}, my bufout is {hello soner}
pid:[9190], fcntl: Bad file descriptor
read: Bad file descriptor
[9190]:my bufin is {empty}, my bufout is {hello soner}
c linux pipe
1个回答
0
投票

如果写入返回成功,则子进程还没有执行

close
。您声称孩子关闭了管道的读取端,但没有任何迹象表明它已经这样做了。

这是一个竞争条件。是家长先喊

write
,还是孩子先喊
close
?第一种情况,写入成功。在后一种情况下,事实并非如此。这两种情况都是可能的,因为没有同步可以确保否则。

© www.soinside.com 2019 - 2024. All rights reserved.