实验 6 进程及进程间的通信 ? 实验目的: 1、 理解进程的概念 2、 掌握进程复制函数fork的用法 3、 掌握替换进程映像exec函数族 4、 掌握进程间的通信机制,包括:有名管道、无名管道、信 号、共享内存、信号量和消息队列 ? 实验要求: 熟练使用该节所介绍fork函数、exec函数族、以及进程间通信的 相关函数。 ? 实验器材: 软件: 1.安装了Ubunt的vmware虚拟机 硬件:PC机一台 ? 实验步骤: 1、 用进程相关API 函数编程一个程序,使之产生一个进程 扇: 父进程产生一系列子进程, 每个子进程打印自己的PID 然 后退出。要求父进程最后打印PID。 进程扇process_fan.c参考代码如下: 2、 用进程相关API 函数编写一个程序,使之产生一个进程 链:父进程派生一个子进程后,然后打印出自己的PID,然后 退出,该子进程继续派生子进程,然后打印PID,然后退出, 以此类推。 要求:1) 实现一个父进程要比子进程先打印PID 的版本。(即 打印的PID 一般是递增的) 2 )实现一个子进程要比父进程先打印PID 的版本。(即打印的PID 一般是递减的) 进程链 1,process_chain1.c 的参考代码如下: 进程链 2,process_chain2.c 的参考代码如下: 3、 编写程序 execl.c,实现父进程打印自己的 pid 号,子进程调用 execl 函数,用可执行程序 file_creat 替换本进程。注意命令行 参数。 参考代码如下: /*execl.c*/ #include #include #include int main(int argc,char *argv[]) { /*判断入参有没有传入文件名*/ if(argc<2) { perror("you haven,t input the filename,please try again!\n"); exit(EXIT_FAILURE); } pid_t result; result=fork(); if(result>0) { printf(“I’m parent,my pid:%d, mysun’s pid %d\n”,getpid(), result); } /* 下面代码是调用 ls 程序, 用可执行程序 ls 替换本进程 if(result==0) { printf(“I’m sum process my pid is %d\n”,getpid()); if(execl("/bin/ls","ls","-l",NULL)<0) { perror("execlp error"); } }*/ /*下面程序调用 execl 函数,用可执行程序 file_creat 替换本 进程*/ if(result==0) { printf(“I’m sum process my pid is %d\n”,getpid()); if(execl("./file_creat","file_creat",argv[1],NULL)<0) perror("execl error!"); } } 其中 file_creat.c 的 代码如下: file_creat.c #include #include #include #include #include void create_file(char *filename) { /*创建的文件具有可读可写的属性*/ if(creat(filename,0666)<0) { printf("create file %s failure!\n",filename); exit(EXIT_FAILURE); } else { printf("create file %s success!\n",filename); } } int main(int argc,char *argv[]) { /*判断入参有没有传入文件名 */ if(argc<2) { perror("you haven't input the filename,please try again!\n"); exit(EXIT_FAILURE); } create_file(argv[1]); exit(EXIT_SUCCESS); } 代码分析 execl 函数会让一个可执行程序运行并替换本进程, 那么这个可执 行程序就应该有创建一个文件的功能。我们可以用 file_creat.c 编译产生的可执行文件 file_creat 来作为该可执行程序。 运行步骤: 1). 编译应用程序 execl.c 和 file_creat.c 命令:gcc execl.c –o execl gcc file_creat.c –o file_creat 2)运行应用程序可以看到运行程序后,创建了新的文件“file” 4、 3). 总结: exec 函数族会在一个进程中启动另一个程序执行。并用它来取代 原调用进程的数据段、代码段和堆栈段。在执行完 exec 函数调用 后,原调用进程的内容除了进程号之外,其他全部被新的进程替 换了。 execlp 函数实例: /*execlp.c*/ #include #include #include 5、 int main() { pid_t result; result=fork(); if(result==0) { if(execlp("ls","ls","-l",NULL)<0) { perror("execlp error"); } } } 代码分析:使用 execlp 函数可以省略指定 ls 的路径,因为 ls 程序在 path 路径中。execlp 函数会到 path 路径中找到可执行程 序。 execv 函数实例 : /*execv.c*/ #include #include #include int main() { pid_t result; char *arg[]={"ls","-l",NULL}; result=fork(); if(result==0) { if(execv("/bin/ls",arg)<0) { perror("execlp error"); } } } 代码分析,execv 函数将可执行程序的运行参数放到数组*arg[] 中。 6、 无名管道实验:用命令行敲入命令: farsight@ubuntu-desktop:~$ ls -l | wc -w 运用所学知识,编程实现上述命令的效果。 ls_wc.c 的参考代码如下: 7、 用命名管道分别写一个服务器程序和一个客户机程序,客户机的 父进程负责每隔一秒产生一个子进程(形成一个进程扇),而每 个子进程则往 FIFO 写入自己的 PID 号码以及一条当前的系统时 间。服务器负责从该 FIFO 中读取数据并将之打印到屏幕上。 multprocess.c 参考代码如下: server.c 的参考代码如下: 实验分析:管道的阻塞情况分析表如下: