dup2()正在使用子进程阻塞吗?C
我正在编写一个函数,将一个输入回显到一个sed,然后是另一个sed。我认为我使用了所有的等待信号,但我能得到的最后一个打印是在echo中的第一个子进程中调用dup2()之前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/[^:]*;"" " "//",
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;
}