ZUCC_操作系统实验_Lab10进程的通信--管道

lab10 进程通信–管道

一.使用pipe创建管道,实现父子进程间的通信

1.代码:

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<unistd.h>

int main(void){
	int data_processed;
	int file_pipes[2];
	
	const char some_data[]="Hello world!";
	char buffer[BUFSIZ+1];
	pid_t fork_result;
	
	memset(buffer,'\0',sizeof(buffer));
	
	if(pipe(file_pipes)==0){
		fork_result=fork();
		if(fork_result==-1){
			fprintf(stderr,"fork failure");
			exit(EXIT_FAILURE);
		}
		
		if(fork_result==0){
			data_processed=read(file_pipes[0],buffer,BUFSIZ);
			printf("Read %d bytes: %s\n",data_processed,buffer);
			exit(EXIT_SUCCESS);
		}
		else{
			data_processed=write(file_pipes[1],buffer,strlen(some_data));
			printf("write %d bytes\n",data_processed);
		} 
	}
	exit(EXIT_SUCCESS);
}
代码释义:使用pipe创建管道,在父子进程间通信
1.pipe()创建管道,fork()创建进程
2.fork()成功,父进程通过write()数据写到管道中
3.子进程用read()从管道中读出数据

运行如图:



二.用sort命令打开管道,然后对一个字符数组排序

1.代码:

#include<stdio.h>
#include<stdlib.h>
#define MAXSTRS 5
int main(){
	int cntr;
	FILE *pipe_fp;     //**
	char *strings[MAXSTRS]={"echo","bravo","alpha","charlie","delta"};
	
	if((pipe_fp=popen("sort","w"))==NULL){
		perror("popen");
		exit(1);
	} 
	
	for(cntr=0;cntr<MAXSTRS;cntr++){
		fputs(strings[cntr],pipe_fp);		//
		fputc('\n',pipe_fp);
	}
	pclose(pipe_fp);
	return 0;
}
代码释义:用sort命令打开一个管道,然后对字符数组排序
1.popen创建管道,并启动“sort"进程
2.如果管道创建成功,将无序数据写到管道中,sort()将无序数据排序

运行如图:



三.两个子进程通过管道传输数据

1.代码:

#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>

int main(){
	pid_t pid1,pid2;
	char *argv1[]={"pstree","-a",0};
	char *argv2[]={"grep","login",0};
	int fd[2];
	
	if(pipe(fd)<0)
		printf("create pipe error");
		
	if((pid1=fork())==0){		//管道上游进程 
		close(fd[0]);			//关闭管道读取端口 
		close(1);				//关闭最初的标准输入 
		dup(fd[1]);				//管道的写入端改为文件描述符1 
		close(fd[1]);				//关闭打开文件描述符的一个副本 
		if(execvp("pstree",argv1)==-1)			//启动运行程序 
			printf("come on");
	}
	
	if((pid2=fork())==0){				//管道下游进程 
		close(fd[1]);					//关闭管道写入端口 
		close(0);						//关闭最初的标准输入 
		dup(fd[0]);						//管道的读取端改为文件描述符的一个副本 
		close(fd[0]);					//关闭打开文件描述符的一个副本 
		execvp("grep",argv2);				//启动运行程序 
	}
	else{
		close(fd[0]);
		close(fd[1]);
		wait(NULL);
		wait(NULL);
	}
	return 0;
} 
代码释义:该例程含有一个父进程和两个子进程,通过管道实现shell命令"pstree|grep login"
实现过程:
1.pipe()创建管道,fork()创建两个子进程,分别居于管道上下游
2.上游进程使用close(pipefd[0])关闭管道读取端,close(1)关闭最初的标准输出,
使用dupipe(pipefd[0])将管道的写入端改为文件描述符1,
使用close(pipefd[1])关闭文件描述符的一个副本,调用execvp启动运行程序
3.下游进程使用close(pipefd[1])关闭管道写入端,使用close(0)关闭最初的标准输入,
使用dup(pipefd[0])将管道的读取端改为文件描述符0,
使用close(pipefd[0])关闭文件描述符的一个副本,调用execvp()启动运行程序

运行如图:



四.多进程的管道通信

1.代码:

#include<stdio.h>
#include<stdlib.h>
#include<signal.h>
#include<unistd.h>

int pid1,pid2;

int main(void){
	int fd[2];
	int i;
	char outpipe[200],inpipe[200];
	pipe(fd);								//创建一个管道 
	while((pid1=fork())==-1);
	if(pid1==0){
		lockf(fd[1],1,0);				 
		for(i=0;i<3;i++){				//把输出串放入数组outpipe中 
			sprintf(outpipe,"child 1 %d %d is sending message\n",i,getpid());
			write(fd[1],outpipe,50);			//向管道写入长为50的串 
			sleep(1);					//自我阻塞1秒 
		}
		lockf(fd[1],0,0);
		exit(0);
	}
	else{
		while((pid2=fork())==-1);
		if(pid2==0){
			lockf(fd[1],1,0);				//互斥 
			for(i=0;i<3;i++){
				sprintf(outpipe,"child 2 %d %d is sending message\n",i,getpid());
				write(fd[1],outpipe,50);
				sleep(1);
			}
			lockf(fd[1],0,0);
			exit(0);
		}
		else{
			wait(0);
			wait(0);					//同步 
			printf("father %d\n",getpid());
			for(i=0;i<6;i++){
				read(fd[0],inpipe,50);			//从管道中读取长为50的串 
				printf("%s\n",inpipe);
			}
		}
	}
} 
代码释义:多进程的管道通信
1.用pipe创建管道,子进程P1,P2分别向管道多次发送数据:
	child 1 is sending message!
	child 2 is sending message!
2.父进程从管道中读取子进程信息并显示

运行如图:


五.编写程序

1.程序要求:(跟着例四代码写就好了)

1.假设系统有三个并发程序:read,move,print,两个共享缓冲区b1,b2;
2.	read:从输入设备记录一个记录,并存入缓冲区b1
	move:从b1中取出一个记录,加工后放入缓冲区b2
	print:取出b2中的一个记录,并打印
3.b1,b2每次只能放一个记录
4.要求三个进程协调,使得打印出来的数据与输入的数据次序,个数完全一致。

2.流程图:

3.代码:

#include<stdio.h>
#include<stdlib.h>
#include<signal.h>
#include<unistd.h>

int pid1,pid2;
int i;
char ch;
void scanfALine(char result[]){		//以一行为输入结果,scanf()以空格或者换行符进行输入结果 
		while(1){
			scanf("%c",&ch);
			if(ch=='\n')
				break;
			result[i++]=ch;
		}
		result[i]='\0';
} 

int main(void){
	int fd0[2],fd1[2];					//管道 
	char readpipe[200],movepipe[200];
	
	pipe(fd0);
	pipe(fd1);							
	
	if(pid1=fork()==0){
		if(pid2=fork()==0){		//孙子进程: 向fd0管道写入 
		
			printf("Read:Please enter:");
			scanfALine(readpipe);
			write(fd0[1],readpipe,50);	
	
			exit(0);			
		}
		else{				  //儿子进程: 从fd0管道读出;修改;向fd1管道写入 
			wait(0);
			
			read(fd0[0],movepipe,50);		//从fd0管道中读出 
			printf("Move: %s\n",movepipe);
			 
			printf("Move:Please modify it:");		// 新写字符串直接覆盖之前的movepipe中的字符串 
			scanfALine(movepipe); 
			write(fd1[1],movepipe,50);			
	
			exit(0);			
		} 
	}
	else{					//父亲进程: 从fd1管道读出
		wait(0);
		wait(0);				

		read(fd1[0],movepipe,50);		
		printf("Print: %s\n",movepipe);
			
		exit(0);		
	} 
} 

//1.lockf()? 
//2.两个管两个向 还是一个管道三个向 ?
//3.为啥写入含空格的字符串出错? 
//4.为什么会覆盖掉之前的字符串? 
//5.为什么修改后写不进去? 

//任务:
//1.完成写入,移动,打印的管道架构
//2.用户自己写入
//3.用户修改 

运行如图:

  • 2
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值