我是Stack Overflow的新手,在C中使用管道时遇到问题。该项目的目标是分叉为两个子进程,B和C,它们向管道写入。然后父进程从管道中读取,而不等待B和C终止。分叉必须使用exec系统调用来完成。这是我的代码
int main()
{
printf("Starting process A, PID: %dn",getpid());
int fd[2];//file descriptors we're using in pipe
int i;//used for while loops
//start the pipe
pipe(fd);
//Spawn process B
int childB=fork();
if (!childB)
{
//Now we're in process B
printf("Forked b says fd[0] is %d and fd[1] is %dn", fd[0], fd[1]);
char *strArg[4];//string array for arguments
//Set up the arguments we'll be using.
strArg[0]= (char*) malloc(1000*sizeof(char));
strArg[1]= (char*) malloc(1000*sizeof(char));
strArg[2]= (char*) malloc(1000*sizeof(char));
strArg[4]=NULL;
printf("After initiliazing strings b says fd[0] is %d and fd[1] is %dn", fd[0], fd[1]);
sprintf(strArg[0], "%s", "PipeW1");
int count=sprintf(strArg[1], "%d", fd[0]);
count=sprintf(strArg[2], "%d", fd[1]);
//We need to close the read end of the pipe before executing the writing code
close(fd[0]);
printf("About to execv B and fd[0] is %d and fd[1] is %dn", fd[0], fd[1]);
//Do the execv call to switch to the different process.
int errcheck=execv("PipeW1", strArg);
if (errcheck==-1)
{
printf("Error opening PipeW1.n");
}
}
//Still in process A. Going to start process C
int childC=fork();
if (!childC)
{
printf("Forked c says fd[0] is %d and fd[1] is %dn", fd[0], fd[1]);
//We're in child C
//Close the read end of pipe before doing any write code
close(fd[0]);
char *strArg[4];//string array for arguments
//Set up the arguments we'll be using.
strArg[0]= (char*) malloc(1000*sizeof(char));
strArg[1]= (char*) malloc(1000*sizeof(char));
strArg[2]= (char*) malloc(1000*sizeof(char));
strArg[4]=NULL;
//Put the name of the program into the appropriate argument
sprintf(strArg[0], "%s", "PipeW2");
int count=sprintf(strArg[1], "%d", fd[0]);
count=sprintf(strArg[2], "%d", fd[1]);
printf("About to execv C and fd[0] is %d and fd[1] is %dn", fd[0], fd[1]);
int errCheck=execv("PipeW2", strArg);
if (errCheck==-1)
{
printf("Error execv Cn");
}
printf("I should have already made C..problem!n");
}
close(fd[1]);//close output, we only read here
//If I wait for B and C to terminate, the program works without incident.
// int retCode;
//wait(&retCode);
//wait(&retCode);
int count=1;
char buffer[110];
i=0;
while(count)//stop the loop when count=0
{
count= read(fd[0], buffer, 100);
buffer[count]=' ';
printf("%sn", buffer);
i++;
if (i%50==0)
{
usleep(200000);
}
}
close(fd[0]);
close(fd[1]);
printf("DEBUG when ending A fd[0] is %d and fd[1] is %dn", fd[0], fd[1]);
printf("Exiting An");
exit(EXIT_SUCCESS);
我遇到的问题是,在执行代码时,我的文件描述符fd[0]和fd[1]分别从[3,4]更改为[0,0],尽管我显然没有操作它们。我遇到的教程都没有很好地解释这一点。
奇怪的是,如果我等待b和c终止,代码就会工作。这是输出
- 启动过程A,PID:27457
- Forked b说fd[0]是3,fd[1]是4
- Forked c说fd[0]是3,fd[1]是4
- 初始化字符串后,b表示fd[0]为0,fd[1]为0
- 即将执行B,fd[0]为0,fd[1]为0
- 即将执行C,fd[0]为0,fd[1]为0
- 现在我们进入进程C,pid:27459
- 启动B
- 将字符串导入B后,fd[0]为0,fd[1]为0
- 退出C
- B退出
- B结束后,fd[0]为0,fd[1]为0
- 结束时调试fd[0]为3,fd[1]为4
- 退出A
因此,当我们在fork中操作字符串参数时,文件描述符会更改为等于零。注意,这似乎发生在execv之前,所以我认为这是在孩子们的其他代码可能影响任何事情之前。
请注意,在使用sprintf将整数转换为字符串之前,整数本身为零。
据我所知,我并没有在任何地方直接操作数组中的整数。因此,我的最佳猜测是,不知何故,管道在某一点上被认为是关闭的,当这种情况发生时,操作系统将所有文件描述符设置为零,但我很难详细找到这一点。
我曾考虑将fd[]文件描述符数组的元素保存为单个整数,以避免指针出现问题,但我怀疑它们存储在数组中是有充分理由的。
我真的很感谢任何关于这个话题的建议!非常感谢。
代码行
strArg[4] = NULL;
足以说明所有观察到的行为。数组的大小为4,这会覆盖末尾,并可能达到fd值。
解决这个问题,如果不起作用,请重新提交您的问题。
strArg[3] = NULL;