前提:
编写程序以向用户查询两个输入字符串。每个输入字符串应该是一个unix命令,允许使用参数。例如,输入1可以是ls -l
,输入2可以是more
。然后程序将创建一个管道和两个子进程。第一个子进程将运行第一个输入中指定的命令。它将输出到管道而不是标准输出。第二个子进程将运行第二个输入中指定的命令。它将从管道输入而不是标准输入。父进程将等待其两个子进程完成,然后整个过程将重复。当输入'@'符号作为第一个命令时,执行将停止。这是我的代码:
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
int main(){
/* Program Termination Symbol */
const char terminate = '@';
/* String delimiter */
const char delimiter = ' ';
/* Pipe file ID's */
int fileID[2];
/* Parent ID's */
int pid1, pid2;
/* String token */
char * token, * token2;
/* User input */
char * user_input, line[100];
user_input = (char *) malloc(100);
/* Unix Commands */
char * command1[10], *command2[10];
for (int i=0; i<10; i++)
{
command1[i] = (char *)malloc(100*sizeof(char));
command2[i] = (char *)malloc(100*sizeof(char));
}
/* Begin main program logic */
printf("Please enter the first command: \n");
user_input = gets(line);
while (user_input[0] != terminate)
{
token = (char *) malloc(100*sizeof(char));
for (int i=0; i<10; i++)
{
if (i == 0)
{
token = strtok(user_input, &delimiter);
} else {
token = strtok(NULL, &delimiter);
}
if (token != NULL)
{
strcpy(command1[i], token);
} else {
command1[i] = 0;
}
}
printf("Please enter the second command: \n");
user_input = gets(line);
token2 = (char *) malloc(100*sizeof(char));
for (int i=0; i<10; i++)
{
if (i == 0)
{
token2 = strtok(user_input, &delimiter);
} else {
token2 = strtok(NULL, &delimiter);
}
if (token2 != NULL)
{
strcpy(command2[i], token2);
} else {
command2[i] = 0;
}
}
/* Pipe and execute user commands */
/* Create pipe */
pipe(fileID);
/* Create child processes */
pid1 = fork();
if (pid1 != 0)
{
pid2 = fork();
}
/* First child process */
if (pid1 == 0)
{
dup2(fileID[1], 1);
execvp(command1[0], command1);
}
/* Second child process */
if (pid2 == 0)
{
dup2(fileID[0], 0);
execvp(command2[0], command2);
}
/* Wait for children to terminate */
wait(&pid1);
wait(&pid2);
/* Repeat */
printf("Please enter the first command: \n");
user_input = gets(line);
}
return 0;
}
我遇到的问题是我的等待。如果我有两个,这对我来说是有意义的(每个孩子一个等待)然后程序在执行第一个管道后冻结。如果我删除了第二个等待,那么程序将再次开始循环,但是不会接受除了enter之外的键盘输入,并且会产生段错误。因此,对于两种等待,输入和输出都是......
Please enter the first command:
ls
Please enter the second command:
more
Pipe
Pipe.c
Pipe.c~
......然后它锁定了。如果我删除第二个等待,输入/输出是......
Please enter the first command:
ls
Please enter the second command:
more
Pipe
Pipe.c
Pipe.c~
Please enter the first command:
(I hit enter, nothing else will work)
Segmentation fault
有人有什么建议吗?这显然与等待这两个过程有关,但我对如何处理它感到茫然。
这个程序现在100%正常运行 - 非常感谢大家的帮助!堆栈溢出一直是互联网上最好的资源之一。非常感谢你花时间查看我的代码并给我你的建议。
答案 0 :(得分:5)
我同意托拉克所说的一切,但为了解决你的问题,你需要关闭你的管道。我认为你正在“悬挂”,因为管道仍处于打开状态。
所以在父母中,就在“等待”之前,我会关闭管道。
close(fileID[0]);
close(fileID[1]);
wait(&pid_status);
wait(&pid_status);
然后,在每个execvp之前,我会关闭孩子不会使用的管道的末端:
close(fileID[0]);
dup2(fileID[1], 1);
execvp(command1[0], command1);
close(fileID[1]);
dup2(fileID[0], 0);
execvp(command2[0], command2);
这应该解决你的问题。除了torak提出的建议之外,我还建议使用fgets代替gets来防止缓冲区溢出。
答案 1 :(得分:4)
有几件事。不确定它们是否是导致问题的原因,但在提交作业之前仍需要考虑。
我认为您没有正确使用wait
。根据{{3}},它不会将pid指针作为参数。
每次循环时,都会为token
和token2
调用malloc,但我没有看到相应的内存释放。
你写了一个单片函数。良好的编码实践会建议将其分解为子程序集合
最后,它可能与第3点有关,以下两行代码在代码中出现两次。再次,它不是一个错误,而是不必要的重复,而且不够优雅。
printf(“请输入第一个命令:\ n”); user_input = gets(line);
答案 2 :(得分:1)
首先,你还要从子进程中调用wait
[编辑:不,你不是,因为每个孩子都调用了execvp]。
此外,wait
不会指向孩子的pid指针,而是指向将写入进程状态的变量(这意味着你要扔掉孩子的pid)。
最后,尝试将waitpid
与“WNOHANG”选项一起使用。它不会挂起,您可以在执行其他操作时将它们放在循环中,并且可以通过检查状态变量来检查子进程是否已退出。 man waitpid
。