一、实验目的:
(1)熟悉Linux下的应用程序开发
(2)熟悉Linux的进程控制原语的使用
(3)掌握Linux操作系统的进程间通信机制管道的使用。
(4)掌握Linux操作系统中父进程与子进程的同步。
二、实验原理:
(1)进程创建函数pid_t fork(void)。返回值:fork函数被正确调用后,将会返回两次!!(通过返回值,可以确定是在父进程中返回还是子进程中返回)
在子进程中返回其返回值为0(不合法的PID,因为PID=0的进程是交换进程);在父进程中返回其返回值为子进程ID(可以让父进程知道所创建的子进程ID号)
;出错返回-1。
- 管道创建函数int pipe(int fildes[2]);pipe函数创建一个通信缓冲区,程序可以通过文件描述符fildes[0]和fildes[1]来访问这个缓冲区:filedes[0]为读而打开,filedes[1]为写而打开;写入fildes[1]的数据可以按照先进先出的顺序从fildes[0]中读出。
(3)读管道函数ssize_t read( int filedes, void *buf, size_t nbytes);第一个参数为管道读文件描述符(pipe函数获取的fildes[0]);第二个参数为读缓冲区的指针,第三个参数为希望读取的字节数。read函数从打开的管道文件中读数据。如成功,则返回实际读到的字节数,如已到达管道文件的末尾或无数据可读,则返回0。
(4)写管道函数ssize_t write( int filedes, const void *buf, size_t nbytes);第一个参数为管道写文件描述符(pipe函数获取的fildes[1] );第二个参数为写缓冲区的指针,第三个参数为希望写入的字节数。该函数返回实际写的字节数,通常与参数nbytes的值相同,否则表示出错。
(5)关闭管道函数int close( int filedes );该函数关闭管道的读文件和写文件,参数为读文件和写文件的文件描述符;进程关闭管道读/写文件后,就不能再通过该文件描述符读/写管道。
(6)进程间同步控制。可以利用pid_t waitpid(pid_t pid,int *status,int options)函数实现进程间的同步控制。参数pid:一个进程ID:pid>0时,只等待进程ID等于pid的子进程,不管其它已经有多少子进程运行结束退出了,只要指定的子进程还没有结束,waitpid就会一直等下去。 pid=-1时,等待任何一个子进程退出,没有任何限制,此时waitpid和wait的作用一模一样。pid=0时,等待同一个进程组中的任何子进程,如果子进程已经加入了别的进程组,waitpid不会对它做任何理睬。pid<-1时,等待一个指定进程组中的任何子进程,这个进程组的ID等于pid的绝对值。参数status:子进程的结束状态值会由参数 status 返回,而子进程的进程识别码也会一起返回。如果不在意结束状态值,则参数 status 可以设成 NULL。参数options:options提供了一些额外的选项来控制waitpid,目前在Linux中只支持WNOHANG和WUNTRACED两个选项,这是两个常数,可以用“|”运算符把它们连接起来使用。不需要时可以传入0。
三、实验内容:
(1)父进程首先使用系统调用pipe()建立一个管道,然后使用系统调用fork() 创建子进程1:子进程1关闭管道读文件;子进程1通过文件I/O操作向管道写文件写一句话(向文件中写入字符串):Child process 1 is sending a message! ;然后子进程1调用exit()结束运行。
(2)父进程再次使用系统调用fork() 创建子进程2:子进程2关闭管道读文件;子进程2通过文件I/O操作向管道写文件写一句话(向文件中写入字符串):Child process 2 is sending a message! ;然后子进程2调用exit()结束运行。
(3)父进程关闭管道写文件,父进程通过文件I/O操作从管道读文件中读出来自于两个子进程的信息,通过printf语句打印输出在屏幕上.
参考代码如下:
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<string.h>
#include<sys/types.h>
#define BUFF_SIZE 2
int main(){char *bufout[BUFF_SIZE] = {"Child process 1 is sending a message!","Child process 2 is sending a message!"}; // 写入消息缓冲区char *bufin[BUFF_SIZE]; // 读取消息缓冲区int fd[2]; //管道文件描述符pid_t childpid1,childpid2; // 子进程pidint s1_len,s2_len;if(pipe(fd) == -1){ // 创建管道失败printf("Failed to create pip!!!");exit(1);}childpid1 = fork(); // 创建子进程1if(childpid1 == -1){printf("Failed to fork!!!");exit(1);}if(childpid1 == 0){ //子进程close(fd[0]); // 关闭管道读文件s1_len = strlen(bufout[0]);write(fd[1],bufout[0],s1_len); // 写入信息exit(0);} else { // 父进程waitpid(childpid1,NULL,0);}childpid2 = fork();// 创建子进程2if(childpid2 == -1){printf("Failed to fork!!!");exit(1);}if(childpid2 == 0){ //子进程close(fd[0]); // 关闭管道读文件s2_len = strlen(bufout[1]);write(fd[1],bufout[1],s2_len); // 写入信息exit(0);} else{ // 父进程waitpid(childpid2,NULL,0);}close(fd[1]); // 关闭通道写文件read(fd[0],bufin[0],s1_len);read(fd[0],bufin[1],s2_len);printf("父进程从管道读取子进程1写入的消息为:%s\n",bufout[0]);printf("父进程从管道读取子进程2写入的消息为:%s\n",bufout[1]);return 1;
}