“试着跑”;ls“grep r”;加上;execvp();
我在两个子进程之间创建了一个“试着跑”;ls“grep r”;加上;execvp();,c,C,我在两个子进程之间创建了一个管道, 首先,我运行ls,它会写入正确的fd, 然后,我运行grepr,它从正确的fd读取 我可以在终端中看到grep命令工作正常(输出) 问题是,grep没有退出,它仍然留在那里,即使ls不再运行 对于其他程序,管道工作正常 for (i = 0; i < commands_num ; i++) { //exec all the commands instants if (pcommands[i]._flag_pipe_out == 1) { //
管道
,
首先,我运行ls
,它会写入正确的fd,
然后,我运行grepr
,它从正确的fd读取
grep
命令工作正常(输出)grep
没有退出,它仍然留在那里,即使ls
不再运行管道
工作正常
for (i = 0; i < commands_num ; i++) { //exec all the commands instants
if (pcommands[i]._flag_pipe_out == 1) { //creates pipe if necessary
if (pipe(pipe_fd) == -1) {
perror("Error: \"pipe()\" failed");
}
pcommands[i]._fd_out = pipe_fd[1];
pcommands[i+1]._fd_in = pipe_fd[0];
}
pid = fork(); //the child exec the commands
if (pid == -1) {
perror("Error: \"fork()\" failed");
break;
} else if (!pid) { //child process
if (pcommands[i]._flag_pipe_in == 1) { //if there was a pipe to this command
if (dup2(pcommands[i]._fd_in, STDIN) == -1) {
perror("Error: \"dup2()\" failed");
exit(0);
}
close(pcommands[i]._fd_in);
}
if (pcommands[i]._flag_pipe_out == 1) { //if there was a pipe from this command
if (dup2(pcommands[i]._fd_out, STDOUT) == -1) {
perror("Error: \"dup2()\" failed");
exit(0);
}
close(pcommands[i]._fd_out);
}
execvp(pcommands[i]._commands[0] , pcommands[i]._commands); //run the command
perror("Error: \"execvp()\" failed");
exit(0);
} else if (pid > 0) { //father process
waitpid(pid, NULL, WUNTRACED);
}
}
//closing all the open fd's
for (i = 0; i < commands_num ; i++) {
if (pcommands[i]._fd_in != STDIN) { //if there was an other stdin that is not 0
close(pcommands[i]._fd_in);
}
if (pcommands[i]._fd_out != STDOUT) { //if there was an other stdout that is not 1
close(pcommands[i]._fd_out);
}
}
现在,循环将执行两次(因为我有两个命令实例)
第一次,它将看到pcommands[0]的pipeout==1
创建管道
叉
pcommands[0]的管道输出==1
孩子:把2个复制到stdout
执行
第二次:
不创建管道
叉
儿童:
pcomands[1]的pipein==1
然后:将2复制到输入
埃克塞普
此命令有效,我的输出为:
errors.log exer2.pdf多路径尝试
(所有带“r”的东西)
但随后它就卡住了,无法从grep
中退出。。
在另一个终端中,我可以看到grep
仍在工作
我希望我关闭所有需要关闭的fd
我不明白为什么它不工作,似乎我做得对(好吧,它适用于其他命令…)
有人能帮忙吗?谢谢您没有关闭足够的管道文件描述符 经验法则:
- 如果使用
或dup()
将管道文件描述符复制到标准输入或标准输出,则应关闭两个原始管道文件描述符dup2()
waitpid()
应该出现在启动子循环的外部。您还需要在等待之前关闭父进程中的管道;否则,读取管道的子级将永远看不到EOF(因为理论上,父级可以写入管道,即使它不会)
您有名称以下划线开头的结构成员。那很危险。以下划线开头的名称保留用于实现。C标准规定:
ISO/IEC 9899:2011§7.1.3保留标识符
-以下划线和大写字母或其他字母开头的所有标识符
下划线始终保留供任何使用。-所有以下划线开头的标识符始终保留用作标识符 文件范围在普通和标记名空间中 这意味着,如果你遇到问题,那么问题是你的,而不是系统的。显然,您的代码是有效的,但是您应该意识到可能遇到的问题,避免这些问题是最明智的
示例代码 这是基于上述代码的固定SSCCE:
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <unistd.h>
typedef struct Command Command;
struct Command
{
int _fd_out;
int _fd_in;
int _flag_pipe_in;
int _flag_pipe_out;
char **_commands;
};
typedef int Pipe[2];
enum { STDIN = STDIN_FILENO, STDOUT = STDOUT_FILENO, STDERR = STDERR_FILENO };
int main(void)
{
char *ls_cmd[] = { "ls", 0 };
char *grep_cmd[] = { "grep", "r", 0 };
Command commands[] =
{
{
._fd_in = 0, ._flag_pipe_in = 0,
._fd_out = 1, ._flag_pipe_out = 1,
._commands = ls_cmd,
},
{
._fd_in = 0, ._flag_pipe_in = 1,
._fd_out = 1, ._flag_pipe_out = 0,
._commands = grep_cmd,
}
};
int commands_num = sizeof(commands) / sizeof(commands[0]);
/* Allow valgrind to check memory */
Command *pcommands = malloc(commands_num * sizeof(Command));
for (int i = 0; i < commands_num; i++)
pcommands[i] = commands[i];
for (int i = 0; i < commands_num; i++) { //exec all the commands instants
if (pcommands[i]._flag_pipe_out == 1) { //creates pipe if necessary
Pipe pipe_fd;
if (pipe(pipe_fd) == -1) {
perror("Error: \"pipe()\" failed");
}
pcommands[i]._fd_out = pipe_fd[1];
pcommands[i+1]._fd_in = pipe_fd[0];
}
pid_t pid = fork(); //the child exec the commands
if (pid == -1) {
perror("Error: \"fork()\" failed");
break;
} else if (!pid) { //child process
if (pcommands[i]._flag_pipe_in == 1) { //if there was a pipe to this command
assert(i > 0);
assert(pcommands[i-1]._flag_pipe_out == 1);
assert(pcommands[i-1]._fd_out > STDERR);
if (dup2(pcommands[i]._fd_in, STDIN) == -1) {
perror("Error: \"dup2()\" failed");
exit(0);
}
close(pcommands[i]._fd_in);
close(pcommands[i-1]._fd_out);
}
if (pcommands[i]._flag_pipe_out == 1) { //if there was a pipe from this command
assert(i < commands_num - 1);
assert(pcommands[i+1]._flag_pipe_in == 1);
assert(pcommands[i+1]._fd_in > STDERR);
if (dup2(pcommands[i]._fd_out, STDOUT) == -1) {
perror("Error: \"dup2()\" failed");
exit(0);
}
close(pcommands[i]._fd_out);
close(pcommands[i+1]._fd_in);
}
execvp(pcommands[i]._commands[0] , pcommands[i]._commands); //run the command
perror("Error: \"execvp()\" failed");
exit(1);
}
else
printf("Child PID %d running\n", (int)pid);
}
//closing all the open pipe fd's
for (int i = 0; i < commands_num; i++) {
if (pcommands[i]._fd_in != STDIN) { //if there was another stdin that is not 0
close(pcommands[i]._fd_in);
}
if (pcommands[i]._fd_out != STDOUT) { //if there was another stdout that is not 1
close(pcommands[i]._fd_out);
}
}
int status;
pid_t corpse;
while ((corpse = waitpid(-1, &status, 0)) > 0)
printf("Child PID %d died with status 0x%.4X\n", (int)corpse, status);
free(pcommands);
return(0);
}
#包括。您需要接受过去的一些问题!这是什么意思?我该怎么做?在你过去的问题中,如果你认为答案是正确的,你需要通过点击答案有多少选票附近的绿色勾号来接受答案。如果人们看到你不接受任何答案,那么他们就不想回答你的问题。好吧,我不知道。。。我只是觉得我应该用上面的箭头来打分。。。谢谢谢谢,我明天就试试这个。我认为,通过快速阅读,问题在于我没有在叉子后关闭父亲的fd。。。(我以前试过,但出现了一些错误……我会再试一次)生活比这更复杂。在子进程中,您也必须关闭管道的两端,并且考虑到您组织数据结构的方式,这意味着如果子i-1的输入是管道,则子i必须查看其数据结构(关闭管道的输出端),如果其输出是管道,则子i+1必须查看其数据结构(关闭管道的输入端),这毫无疑问是混乱的。您还需要关闭主shell中的管道。我将您的代码反向工程为SSCCE().好的,谢谢,我还没有试过,我稍后再做…我只是想问一下SSCCE的问题是什么?你做了这个更改吗?还是想让我做?我不理解这部分,因为我没有看到代码的更改…我的机器上有可用的代码作为SSCCE;我还没有将其上传到这里(我有“坏”代码-可编译,但不像上面的片段那样工作;我也有“固定”代码-进行了必要的更改)。谢谢,它成功了!就我所知,你是如何做到的,这样它就不会变得“毫无争议的混乱”?我将感谢你的回答!
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <unistd.h>
typedef struct Command Command;
struct Command
{
int _fd_out;
int _fd_in;
int _flag_pipe_in;
int _flag_pipe_out;
char **_commands;
};
typedef int Pipe[2];
enum { STDIN = STDIN_FILENO, STDOUT = STDOUT_FILENO, STDERR = STDERR_FILENO };
int main(void)
{
char *ls_cmd[] = { "ls", 0 };
char *grep_cmd[] = { "grep", "r", 0 };
Command commands[] =
{
{
._fd_in = 0, ._flag_pipe_in = 0,
._fd_out = 1, ._flag_pipe_out = 1,
._commands = ls_cmd,
},
{
._fd_in = 0, ._flag_pipe_in = 1,
._fd_out = 1, ._flag_pipe_out = 0,
._commands = grep_cmd,
}
};
int commands_num = sizeof(commands) / sizeof(commands[0]);
/* Allow valgrind to check memory */
Command *pcommands = malloc(commands_num * sizeof(Command));
for (int i = 0; i < commands_num; i++)
pcommands[i] = commands[i];
for (int i = 0; i < commands_num; i++) { //exec all the commands instants
if (pcommands[i]._flag_pipe_out == 1) { //creates pipe if necessary
Pipe pipe_fd;
if (pipe(pipe_fd) == -1) {
perror("Error: \"pipe()\" failed");
}
pcommands[i]._fd_out = pipe_fd[1];
pcommands[i+1]._fd_in = pipe_fd[0];
}
pid_t pid = fork(); //the child exec the commands
if (pid == -1) {
perror("Error: \"fork()\" failed");
break;
} else if (!pid) { //child process
if (pcommands[i]._flag_pipe_in == 1) { //if there was a pipe to this command
assert(i > 0);
assert(pcommands[i-1]._flag_pipe_out == 1);
assert(pcommands[i-1]._fd_out > STDERR);
if (dup2(pcommands[i]._fd_in, STDIN) == -1) {
perror("Error: \"dup2()\" failed");
exit(0);
}
close(pcommands[i]._fd_in);
close(pcommands[i-1]._fd_out);
}
if (pcommands[i]._flag_pipe_out == 1) { //if there was a pipe from this command
assert(i < commands_num - 1);
assert(pcommands[i+1]._flag_pipe_in == 1);
assert(pcommands[i+1]._fd_in > STDERR);
if (dup2(pcommands[i]._fd_out, STDOUT) == -1) {
perror("Error: \"dup2()\" failed");
exit(0);
}
close(pcommands[i]._fd_out);
close(pcommands[i+1]._fd_in);
}
execvp(pcommands[i]._commands[0] , pcommands[i]._commands); //run the command
perror("Error: \"execvp()\" failed");
exit(1);
}
else
printf("Child PID %d running\n", (int)pid);
}
//closing all the open pipe fd's
for (int i = 0; i < commands_num; i++) {
if (pcommands[i]._fd_in != STDIN) { //if there was another stdin that is not 0
close(pcommands[i]._fd_in);
}
if (pcommands[i]._fd_out != STDOUT) { //if there was another stdout that is not 1
close(pcommands[i]._fd_out);
}
}
int status;
pid_t corpse;
while ((corpse = waitpid(-1, &status, 0)) > 0)
printf("Child PID %d died with status 0x%.4X\n", (int)corpse, status);
free(pcommands);
return(0);
}