dup2()正在使用子进程阻塞吗?C

dup2()正在使用子进程阻塞吗?C,c,pipe,fork,wait,dup,C,Pipe,Fork,Wait,Dup,我正在编写一个函数,将一个输入回显到一个sed,然后是另一个sed。我认为我使用了所有的等待信号,但我能得到的最后一个打印是在echo中的第一个子进程中调用dup2()之前 void sendbc (char * str_ ) { int fd[2]; int fd1[2]; int pid,pid1; char* echo[] = {"echo", str_,NULL}; char* sed1[] = {"sed","s/[^:]*;"" " "//",

我正在编写一个函数,将一个输入回显到一个sed,然后是另一个sed。我认为我使用了所有的等待信号,但我能得到的最后一个打印是在echo中的第一个子进程中调用dup2()之前

void sendbc (char * str_ ) {
    int fd[2];
    int fd1[2];
    int pid,pid1;
    char* echo[] = {"echo", str_,NULL};
    char* sed1[] = {"sed","s/[^:]*;"" " "//",NULL};
    char* sed2[] = {"sed","s/[^:]*."" " "//",NULL};
    int status,er;
    FILE *f;
    if(pipe(fd) < 0){
        exit(100);
    }
    if(pipe(fd1) < 0){
        exit(100);
    }

    pid = fork();
    if (pid == 0) {
        dup2(fd[1], 1) //last command before blocking
        close(fd[1]);
        close(fd[0]);
        execvp(echo[0], echo);
        printf("Error in execvp1\n");
    }else{
        wait(&status);
        pid = fork();
        if (pid == 0){
            dup2(fd[0], 0);
            dup2(fd1[1], 1);
            dup2(fd1[1], 2);
            close(fd[1]);
            close(fd[0]);
            close(fd1[1]);
            close(fd1[0]);
            execvp(sed1[0],sed1);
            printf("Error in execvp2\n");
        }else{
            wait(&status);
            dup2(fd1[0],0);
            dup2(1,2);
            //dup2(1,1);
            close(fd1[1]);
            close(fd1[0]);
            execvp(sed2[0],sed2);
            printf("Error in execvp3\n");
        }
    }

    if(pid!=0)
        wait(&status);
    close(fd[0]);
    close(fd[1]);
    close(fd1[1]);
    close(fd1[0]);
}
void sendbc(char*str){
int-fd[2];
int-fd1[2];
int-pid,pid1;
char*echo[]={“echo”,str_2;,NULL};
char*sed1[]={“sed”,“s/[^::]*;“”“/”,NULL};
char*sed2[]={“sed”,“s/[^:][*。”“/”,NULL};
国际地位,呃,;
文件*f;
如果(管道(fd)<0){
出口(100);
}
如果(管道(fd1)<0){
出口(100);
}
pid=fork();
如果(pid==0){
dup2(fd[1],1)//阻塞前的最后一个命令
关闭(fd[1]);
关闭(fd[0]);
execvp(echo[0],echo);
printf(“execvp1中的错误”);
}否则{
等待(&状态);
pid=fork();
如果(pid==0){
dup2(fd[0],0);
dup2(fd1[1],1);
dup2(fd1[1],2);
关闭(fd[1]);
关闭(fd[0]);
关闭(fd1[1]);
关闭(fd1[0]);
execvp(sed1[0],sed1);
printf(“execvp2\n中的错误”);
}否则{
等待(&状态);
dup2(fd1[0],0);
dup2(1,2);
//dup2(1,1);
关闭(fd1[1]);
关闭(fd1[0]);
execvp(sed2[0],sed2);
printf(“execvp3中的错误”);
}
}
如果(pid!=0)
等待(&状态);
关闭(fd[0]);
关闭(fd[1]);
关闭(fd1[1]);
关闭(fd1[0]);
}
我可以想象两种可能性。。。dup2正在阻塞,或者我需要创建更多进程,因为它会在调用时结束进程,但在快速阅读他的手册页后,这听起来不太正确。。。可能是什么问题?

一般问题 在各个进程中,您没有关闭足够的文件描述符


经验法则:如果 将管道的一端连接到标准输入或标准输出,关闭两个 返回的原始文件描述符 尽快。 特别是,在使用任何 函数族

如果将描述符与 或 使用
F_DUPFD
F_DUPFD\u CLOEXEC


如果父进程不通过 在安装管道时,必须确保管道两端提前关闭 足够的(例如,在等待之前)让它的孩子可以接受 读取(或获取信号管信号或写入错误)时的EOF指示 写入),而不是无限期地阻塞。 即使父级使用管道而不使用
dup2()
,它也应该 通常情况下,至少关闭管道的一端-这是非常罕见的 在单个管道两端读写的程序

请注意,
O_CLOEXEC
选项 , 而
fcntl()
FD\u CLOEXEC
F\u DUPFD\u CLOEXEC
选项也可以考虑 我开始讨论这个问题

如果你使用 及其广泛的支持功能系列(共21项功能), 您将需要查看如何在生成的进程中关闭文件描述符 (, 等等)

请注意,使用
dup2(a,b)
比使用
close(b)更安全;dup(a)
由于种种原因。
一个是,如果要强制文件描述符的大小大于
通常的数字,
dup2()
是唯一可行的方法。 另一个是,如果
a
b
相同(例如,两者都
0
),则
dup2()
正确处理它(在复制
a
之前,它不会关闭
b
) 而单独的
close()
dup()
却失败得很厉害。 这不太可能,但并非不可能


具体问题
  • 为了安全起见,您没有关闭足够的文件描述符
  • 你的正则表达式是可疑的
  • 您不应该让管道中的进程互相等待
宠物皮:当我有两个密切相关的变量,如管道文件描述符对时,我更喜欢使用
fd1
fd2
;我觉得
fd
fd1
之类的东西很愚蠢。但是,您可以选择忽略这一点。

工作代码
#包括
#包括
#包括
静态无效转储_argv(字符**argv)
{
printf(“%d:\n”,getpid());
而(*argv!=NULL)
{
printf(“%d:\n”,getpid(),*argv++);
}
}
静态void sendbc(char*str)
{
int-fd1[2];
int-fd2[2];
int-pid;
char*echo[]={“echo”,str,NULL};
char*sed1[]={“sed”,“s/[^:][*[;]//”,NULL};
char*sed2[]={“sed”,“s/[^:][.]/”,NULL};
如果(管道(fd1)<0)
出口(100);
如果(管道(fd2)<0)
出口(101);
printf(“%d:正在工作\n”,getpid());
pid=fork();
if(pid<0)
出口(102);
否则如果(pid==0)
{
printf(“%d:child 1-echo\n”,getpid());
dump_argv(echo);
dup2(fd1[1],1);
关闭(fd1[1]);
关闭(fd1[0]);
关闭(fd2[0]);
关闭(fd2[1]);
execvp(echo[0],echo);
fprintf(stderr,“execvp1中的错误”);
出口(103);
}
其他的
{
printf(“%d:parent-在第二个fork之前\n”,getpid());
pid=fork();
如果(pid==0)
{
printf(“%d:child 2-sed 1\n”,getpid());
转储argv(sed1);
dup2(fd1[0],0);
dup2(fd2[1],1);
关闭(fd1[1]);
关闭(fd1[0]);
关闭(fd2[1]);
关闭(fd2[0]);
execvp(sed1[0],sed1);
fprintf(stderr,“execvp2中的错误”);
出口(104);
}
其他的
{
printf(“%d:parent-sed 2\n”,getpid());
转储argv(sed1);
dup2(fd2[0],0);
关闭(fd1[1]);
关闭(fd1[0]);
关闭(fd2[1]);
关闭(fd2[0]);
execvp(sed2[0],sed2);
fprintf(stderr,“execvp3中的错误”);
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

static void dump_argv(char **argv)
{
    printf("%d:\n", getpid());
    while (*argv != NULL)
    {
        printf("%d: <<%s>>\n", getpid(), *argv++);
    }
}

static void sendbc(char *str)
{
    int fd1[2];
    int fd2[2];
    int pid;
    char *echo[] = {"echo", str, NULL};
    char *sed1[] = {"sed", "s/[^:]*[;]//", NULL};
    char *sed2[] = {"sed", "s/[^:]*[.]//", NULL};
    if (pipe(fd1) < 0)
        exit(100);
    if (pipe(fd2) < 0)
        exit(101);

    printf("%d: at work\n", getpid());
    pid = fork();
    if (pid < 0)
        exit(102);
    else if (pid == 0)
    {
        printf("%d: child 1 - echo\n", getpid());
        dump_argv(echo);
        dup2(fd1[1], 1);
        close(fd1[1]);
        close(fd1[0]);
        close(fd2[0]);
        close(fd2[1]);
        execvp(echo[0], echo);
        fprintf(stderr, "Error in execvp1\n");
        exit(103);
    }
    else
    {
        printf("%d: parent - before second fork\n", getpid());
        pid = fork();
        if (pid == 0)
        {
            printf("%d: child 2 - sed 1\n", getpid());
            dump_argv(sed1);
            dup2(fd1[0], 0);
            dup2(fd2[1], 1);
            close(fd1[1]);
            close(fd1[0]);
            close(fd2[1]);
            close(fd2[0]);
            execvp(sed1[0], sed1);
            fprintf(stderr, "Error in execvp2\n");
            exit(104);
        }
        else
        {
            printf("%d: parent - sed 2\n", getpid());
            dump_argv(sed1);
            dup2(fd2[0], 0);
            close(fd1[1]);
            close(fd1[0]);
            close(fd2[1]);
            close(fd2[0]);
            execvp(sed2[0], sed2);
            fprintf(stderr, "Error in execvp3\n");
            exit(105);
        }
    }
    fprintf(stderr, "Reached unexpectedly\n");
    exit(106);
}

int main(void)
{
    char message[] =
        "This is the first line\n"
        "and this is the second - with a semicolon ; here before a :\n"
        "and the third line has a colon : before the semicolon ;\n"
        "but the fourth line has a dot . before the colon\n"
        "whereas the fifth line has a colon : before the dot .\n"
    ;

    sendbc(message);
    return 0;
}