C 产生了一个bash shell。外壳死了,但管道没有破裂? 问题

C 产生了一个bash shell。外壳死了,但管道没有破裂? 问题,c,linux,bash,shell,pipe,C,Linux,Bash,Shell,Pipe,我正在尝试将内容从主例程传输到execvp的bash shell。我遇到了一个问题,当我在子shell中写入“exit”时,它并没有告诉我管道真的断了。应该是的,对吧?进程终止,因此管道fd也应返回EOF或SIGPIPLE。但事实并非如此,它只是像平常一样继续读/写 代码 代码附于此处: /************************************************************ *包括: *ioctl-无用(?) *termios、tcsetattr、tcgeta

我正在尝试将内容从主例程传输到execvp的bash shell。我遇到了一个问题,当我在子shell中写入“exit”时,它并没有告诉我管道真的断了。应该是的,对吧?进程终止,因此管道fd也应返回EOF或SIGPIPLE。但事实并非如此,它只是像平常一样继续读/写

代码 代码附于此处:

/************************************************************
*包括:
*ioctl-无用(?)
*termios、tcsetattr、tcgetattr-用于设置
*非规范的,一次字符终端。
*fork,exec-为第2部分创建子进程。
*pthread,pipe-创建用于通信的管道进程
*带着孩子的壳。
*kill-退出进程
*atexit-进行一些清理。用于termios、tcsetattr、,
*tcgetattr。
************************************************************/
#包含//ioctl
#包括//termios、tcsetattr、tcgetattr
#包括//fork、exec、pipe
#包括//waitpid
#包含//pthread
#包括//kill
#包括退出
#包括//fprintf和其他实用程序函数
#包括//getopt
/**********************
*全球的
**********************/
pid_t pid;
/**********************
*常数
**********************/
静态常量int缓冲区大小=16;
静态常数int STDIN_FD=0;
静态常数int STDOUT_FD=1;
静态常数int STDERR_FD=2;
//这些属性稍后将恢复为
结构termios保存的\u属性;
//还原保存的属性的步骤
无效的
重置输入模式(无效){
tcsetattr(标准文件号、TCSANOW和保存的属性);
}
//将输入模式设置为正确的非规范模式。
无效的
设置输入模式(无效){
结构termios tattr;
/*确保stdin是一个终端*/
如果(!isatty(标准文件号))
{
fprintf(stderr,“不是终端。\n”);
退出(退出失败);
}
/*保存终端属性,以便稍后恢复它们*/
tcgetattr(标准输入文件号和保存的属性);
atexit(复位输入模式);
/*设置有趣的终端模式*/
tcgetattr(标准文件号和tattr);
tattr.c_lflag&=~(ICANON | ECHO);/*清除ICANON和ECHO*/
tattr.c_cc[VMIN]=1;
tattr.c_cc[VTIME]=0;
tcsetattr(标准文件号、TCSAFLUSH和tattr);
}
//pthread 1将从pipe_fd[0]中读取数据,这
//真的是孩子的烟斗(stdout)。
//然后打印出内容。
void*线程读取(void*arg){
int*pipe_fd=((int*)arg);
int read_fd=pipe_fd[0];
int write_fd=pipe_fd[1];
字符c;
而(1){
int bytes_read=read(read_fd,&c,1);
如果(字节读取>0){
普查尔(c);
}
否则{
关闭(读取fd);
关闭(写入fd);
fprintf(stdout,“读坏了”);
fflush(stdout);
打破
}
}
}
//pthread 2将写入child_pipe_fd[1],它将
//这真是孩子的标准。
//但除了写信给child_pipe_fd[1]之外,
//我们还必须打印出我们的
//辩论进入了终点站。(因此pthread 2
//额外收费)。
void*线程写入(void*arg){
设置输入模式();
int*管道参数=((int*)参数);
int child_read_fd=管道参数[0];
int child_write_fd=管道参数[1];
int parent_read_fd=管道参数[2];
int parent_write_fd=管道参数[3];
字符c;
而(1){
int bytes_read=read(标准字节数FD和c,1);
写入(子项写入fd和c、字节读取);
普查尔(c);
如果(c==0x04){
//如果检测到EOF,则
//我们需要关闭管道。
关闭(子项写入fd);
关闭(儿童读入fd);
关闭(父项写入fd);
关闭(父项读取fd);
杀死(pid、SIGHUP);
打破
}
}
}
int main(int argc,char*argv[]){
/***************************
*这里的Getopt进程用于--shell
**************************/
int child_pipe_fd[2];
int parent_pipe_fd[2];
管道(儿童管道);
管道(母管道);
//我们需要生成一个次外壳。
pid=fork();
if(pid<0){
perror(“分叉不成功。退出”);
退出(退出失败);
}
如果(pid==0){//是子级,则为else。
//我们重复fd并关闭管道。
close(0);//关闭stdin。子管道应为。
dup(child_pipe_fd[0]);//pipe_fd[0]是读取。使读取成为标准输入。
关闭(子管道[0]);
关闭(1);//关闭标准输出
dup(parent_pipe_fd[1]);//pipe_fd[1]是write。将write设为标准输出。
关闭(父管道[1]);
char*BASH[]={“/bin/BASH”,NULL};
execvp(BASH[0],BASH);
}
else{//是父对象
//我们重复fd并关闭管道。
//
//创建2个pthread。
//pthread 1将从pipe_fd[0]中读取数据,这
//真的是孩子的烟斗(stdout)。
//然后打印出内容。
//
//pthread 2将写入管道_fd[1],该管道
//真的是孩子的烟斗吗
//但除了向pipe_fd[1]写信之外,
//我们还必须打印出我们的
//参数已插入终端。(因此pthread 2
//额外收费)。
//
//我们还需要注意信号处理:
信号(SIGINT,SIGINT_处理器);
/*信号(信号管、信号管处理装置)*/
int write_args[]={child_pipe_fd[0],child_pipe_fd[1],
父管道\u fd[0],父管道\u fd[1]};
pthread_t[2];
pthread_create(t,NULL,thread_read,parent_pipe_fd);
pthread_create(t+1,NULL,thread_write,write_args);
pthread_join(t[0],NULL);
pthread_join(t[1],NULL);
智力状态;
if(waitpid(pid和status,0)=-1){
perror(“等待孩子失败”);
退出_
else {
  // pid >0; this is the parent
  close(child_pipe_fd[0]);  // ADD THIS LINE
  close(parent_pipe_fd[1]); // ADD THIS LINE