当我运行这段代码时,我的程序被杀了,但我似乎无法找出原因。
int pipefd[2];
pipe(pipefd);
pid = fork();
if(pid == 0){ //child process, receives data from pipe for execution
close(0);
dup(pipefd[0]);
close(pipefd[1]);
execvp(pipeCom2[0], pipeCom2);
}
else if (pid > 1){ //parent process writes data to pipe for execution
close(1);
dup(pipefd[1]);
close(pipefd[0]);
execvp(pipeCom1[0], pipeCom1);
waitpid(pid, &status, WUNTRACED);
}
我一直在测试cat project1.c | grep include命令。它在我的程序中正确显示所有include语句。
所以pipeCom1包含{" cat"," project1.c"}
和pipeCom2包含{" grep"," include"}
在程序的早期,我使用此代码覆盖输出,并在程序结束时恢复正常。因此,当进程被终止时,输出就会搞砸。
newConfig.c_lflag &= ~(ICANON| ECHOE | ECHO);
tcsetattr(0, TCSANOW, &newConfig);
答案 0 :(得分:1)
将评论转移到答案中。
您没有关闭足够的管道文件描述符。如果将描述符复制到标准输入或输出,则应关闭两个管道描述符。
我应该关闭哪些其他管道文件描述符?
你有:
int pipefd[2];
pipe(pipefd);
pid = fork();
if (pid == 0) //child process, receives data from pipe for execution
{
close(0);
dup(pipefd[0]);
close(pipefd[1]);
execvp(pipeCom2[0], pipeCom2);
}
else if (pid > 1) //parent process writes data to pipe for execution
{
close(1);
dup(pipefd[1]);
close(pipefd[0]);
execvp(pipeCom1[0], pipeCom1);
waitpid(pid, &status, WUNTRACED);
}
在调用pipefd[0]
后,您需要在两组代码中同时关闭pipefd[1]
和dup()
。您也可以使用dup2()
代替dup()
;这通常更简单。
在这个带有试用管道的程序中,如果没有添加缺少的close()
操作,那么一切都会很好。但是,一般来说,关闭不需要的管道描述符是至关重要的,因为开放描述符意味着进程不会获得它期望的EOF,或者它应该不会得到SIGPIPE信号或写入错误,因为进程有错误的管道末端仍然打开。
execvp()
此外,父进程包含execvp()
调用;仅当exec失败时才执行以下代码。当进程运行execvp()
(或任何其他exec*()
函数时,只有在执行操作失败时才会返回调用。
如果您需要终端重置,请在其中一个exec调用之前执行,或者创建两个子节点并让父节点关闭其所有管道描述符并等待子节点完成(die),然后重置终端。考虑一下信号处理。在执行其他程序之前重置终端更简单。
在程序的早期,我使用此代码覆盖输出,并在程序结束时恢复正常。因此,当进程被终止时,输出就会搞砸。
newConfig.c_lflag &= ~(ICANON| ECHOE | ECHO); tcsetattr(0, TCSANOW, &newConfig);
假设您有一个oldConfig
来自tcgetattr()
的输出,您应该这样做:
tcsetattr(0, TCSANOW, &oldConfig);
在父进程运行execvp()
之前。
你说:
pipeCom1包含{“cat”,“project1.c”}
和pipeCom2包含{“grep”,“include”}
正确操作至关重要pipeCom1
和pipeCom2
都有一个空(指针)终止的参数字符串列表。例如,您可以使用以下硬连线参数列表:
char *pipeCom1[] = { "cat", "project1.c", 0 };
char *pipeCom2[] = { "grep", "include", 0 };
如果您愿意,可以用NULL代替0。
execvp()
失败时退出您需要考虑execvp()
失败后应该发生什么。正确的答案很少“继续,好像没有出错”(这是你的代码所做的)。
您应该考虑将错误报告给标准错误。您通常应该使用exit(EXIT_FAILURE);
或_exit(EXIT_FAILURE);
或其中某些亲属退出并显示失败状态。
#include <stdio.h>
#include <termios.h>
#include <stdlib.h>
#include <unistd.h>
int main(void)
{
struct termios oldConfig;
struct termios newConfig;
tcgetattr(0, &oldConfig); // Error check omitted
newConfig = oldConfig;
newConfig.c_lflag &= ~(ICANON| ECHOE | ECHO);
tcsetattr(0, TCSANOW, &newConfig); // Error check omitted
/* Do stuff without echoing enabled */
/* Now do some execution */
char *pipeCom1[] = { "cat", "project1.c", 0 };
char *pipeCom2[] = { "grep", "include", 0 };
int pipefd[2]; // Error check omitted
pipe(pipefd);
pid_t pid = fork();
if (pid == 0) //child process
{
close(0);
dup(pipefd[0]);
close(pipefd[1]);
close(pipefd[0]);
execvp(pipeCom2[0], pipeCom2);
perror(pipeCom2[0]);
exit(EXIT_FAILURE);
}
else if (pid > 1) //parent process
{
close(1);
dup(pipefd[1]);
close(pipefd[0]);
close(pipefd[1]);
tcsetattr(0, TCSANOW, &oldConfig);
execvp(pipeCom1[0], pipeCom1);
perror(pipeCom1[0]);
exit(EXIT_FAILURE);
}
}
假设project1.c
是上述源代码的副本,该命令的输出为:
#include <stdio.h>
#include <termios.h>
#include <stdlib.h>
#include <unistd.h>
char *pipeCom2[] = { "grep", "include", 0 };
,过程结束后终端处于正确的模式。