进程通信实验报告一、实验名称:进程通信二、实验目的:掌握用邮箱方式进行进程通信的方法,并通过设计实现简单邮箱理解进程通信中的同步问题以及解决该问题的方法。
三、实验原理:邮箱机制类似于日常使用的信箱。
对于用户而言使用起来比较方便,用户只需使用send ()向对方邮箱发邮件 receive ()从自己邮箱取邮件, send ()和 receive ()的内部操作用户无需关心。
因为邮箱在内存中实现,其空间有大小限制。
其实send ()和 receive ()的内部实现主要还是要解决生产者与消费者问题。
四、实验内容:进程通信的邮箱方式由操作系统提供形如send ()和receive ()的系统调用来支持,本实验要求学生首先查找资料了解所选用操作系统平台上用于进程通信的系统调用具体形式,然后使用该系统调用编写程序进行进程间的通信,要求程序运行结果可以直观地体现在界面上。
在此基础上查找所选用操作系统平台上支持信号量机制的系统调用具体形式,运用生产者与消费者模型设计实现一个简单的信箱,该信箱需要有创建、发信、收信、撤销等函数,至少能够支持两个进程互相交换信息,比较自己实现的信箱与操作系统本身提供的信箱,分析两者之间存在的异同。
五、背景知识介绍:1、sembuf 数据结构struct sembuf{unsigned short int sem_num; //semaphore numbershort int sem_op; //semaphore operationshort int sem_flg; //operation flag};sem_num :操作信号在信号集中的编号,第一个信号的编号是0。
进程A 进程B 信箱A 信箱B Send()Send() receive() receive()sem_op:如果其值为正数,该值会加到现有的信号内含值中。
通常用于释放所控资源的使用权;如果sem_op的值为负数,而其绝对值又大于信号的现值,操作将会阻塞,直到信号值大于或等于sem_op的绝对值。
通常用于获取资源的使用权;如果sem_op的值为0,则操作将暂时阻塞,直到信号的值变为0。
sem_flg:信号操作标志,可能的选择有两种IPC_NOWAIT //对信号的操作不能满足时,semop()不会阻塞,并立即返回,同时设定错误信息。
IPC_UNDO //程序结束时(不论正常或不正常),保证信号值会被重设为semop()调用前的值。
这样做的目的在于避免程序在异常情况下结束时未将锁定的资源解锁,造成该资源永远锁定。
2、 semop函数函数原型:int semop(int semid, struct sembuf *sops, unsigned nsops);参数说明:semid:信号集的识别码,可通过semget获取。
sops:指向存储信号操作结构的数组指针。
nsops:信号操作结构的数量,恒大于或等于1。
返回说明:成功执行时,两个系统调用都返回0。
失败返回-1,错误信息保存在errno中。
3、semget函数函数原型:int semget(key_t key,int nsems,int semflg);参数说明:key:关键字值一般是由系统调用ftok()返回的nsems:指出了一个新的信号量集中应该创建的信号量的个数semflg:打开和存取操作与参数semflg中的内容相关。
返回说明:如果成功,则返回信号量集的IPC标识符。
如果失败,返回-1,错误信息保存在errno中。
4、semctl函数函数原型:int semctl(int semid,int semnum,int cmd,union semun arg);参数说明:senid:关键字值semnum:信号量数目cmd:要操作的具体命令arg:semnu的一个联合类型的副本。
返回说明:返回值:如果成功,则为一个正数。
如果失败,则为-1。
错误信息保存在errno 中。
5、pthread_create函数函数原型:int pthread_create(pthread_t *restrict tidp,const pthread_attr_t*restrict attr,void*(*start_rtn)(void*),void *restrict arg);参数说明:tidp:指向线程标识符的指针。
attr:用来设置线程属性。
第三个参数是线程运行函数的起始地址。
arg:运行函数的参数。
六、设计方案:1、定义两个数组当作两个邮箱int a_buf[5],b_buf[5];邮箱的容量为5。
2、定义两个指针指向邮箱的顶部int a_buf_top=0,b_buf_top=0;初始时邮箱都为空3、定义semaphore_P和semaphore_V两个函数实现P.V原语操作,用P.V原语实现进程的互斥。
4、定义发送和接收信息的函数,其中void * A_Send(void *arg)为A发送信息,void * B_Send(void *arg)为B发送信息,void *A_Receive(void *arg)为A接收信息;void*B_Receive(void *arg)为B接收信息。
5、调用创建线程函数,让上述四个函数并行运行。
七、预计的实验结果:A_Receive()和 B_Receive()分别接收B_Send()和 A_Send()发出的信息,发送的信息和接受的信息应该一样。
八、关键代码的分析:/***************************************** P原语操作* *************************************/int semaphore_P(int sem_id){struct sembuf p;p.sem_num=0;p.sem_op=-1;p.sem_flg=SEM_UNDO;if(semop(sem_id,&p,1)==-1){printf(errno);return 0;}return 1;}/**************************************** V原语操作* **********************************/int semaphore_V(int sem_id){struct sembuf v;v.sem_num=0;v.sem_op=1;v.sem_flg=SEM_UNDO;if(semop(sem_id,&v,1)==-1){printf(errno);return 0;}return 1;}/**************************************** A向B发送信息* ************************************/void * A_Send(void *arg){int i;for(i=0;i<10;i++){semaphore_P(sem_idAs); //P操作semaphore_P(a_mutex_semaphore); //互斥int number=rand(); //随机数为发送的邮件printf("A send to B:%d\n",number);b_buf[b_buf_top]=number;//邮箱B中接收A发送的邮件b_buf_top+=1;//A向B发送邮件,B的邮件数量加一semaphore_V(a_mutex_semaphore); //互斥semaphore_V(sem_idBr);//V操作sleep(1);}}九、调试记录:于pthread库不是Linux系统默认的库,连接时需要使用库libpthread.a, 所以在使用pthread_create创建线程时,在编译中要加-lpthread参数 gcc -w -lpthread semaphore.c十、实际的实验结果:ada@ada-desktop:~/OS$ gcc -w -o semaphore -lpthread semaphore.cada@ada-desktop:~/OS$ ./semaphoreB send to A:123A receive from B:123A send to B:222B receive from A: 222B send to A:111A receive from B:111A send to B:12334B receive from A: 12334ada@ada-desktop:~/OS$十一、实验结果分析:四个线程并发运行, A_Send()和 B_Send()发出信息,同时打印出发出的信息内容;A_Receive()和 B_Receive()分别接收B_Send()和 A_Send()发出的信息,并打印出接受的信息内容。
发出的内容和接收的内容一样,符合时间情况。
十二、附代码#include<unistd.h>#include<stdlib.h>#include<stdio.h>#include<pthread.h>#include<semaphore.h>#include<sys/types.h>#include<sys/ipc.h>#include<sys/sem.h>#include<errno.h>int a_buf[5],b_buf[5]; //邮箱的容量为5int a_buf_top=0,b_buf_top=0;//假设初始时邮箱都为空int sem_idAs,sem_idBs; //例如sem_idAs代表A此时最多可以向B发送的邮件数int sem_idAr,sem_idBr; //例如sem_idAr代表A此时邮箱中受到的邮件数int a_mutex_semaphore,b_mutex_semaphore; //互斥信号量/***************************************** P原语操作* *************************************/int semaphore_P(int sem_id)struct sembuf p;p.sem_num=0;p.sem_op=-1;p.sem_flg=SEM_UNDO;if(semop(sem_id,&p,1)==-1){printf(errno);return 0;}return 1;}/**************************************** V原语操作* **********************************/int semaphore_V(int sem_id){struct sembuf v;v.sem_num=0;v.sem_op=1;v.sem_flg=SEM_UNDO;if(semop(sem_id,&v,1)==-1){printf(errno);return 0;}return 1;}/**************************************** A向B发送信息* ************************************/void * A_Send(void *arg){int i;for(i=0;i<10;i++){semaphore_P(sem_idAs); //P操作semaphore_P(a_mutex_semaphore); //互斥int number=rand(); //随机数为发送的邮件printf("A send to B:%d\n",number);b_buf[*b_top] = num++;//邮箱B中接收A发送的邮件,(*b_top)+=1;//A向B发送邮件,B的邮件数量加一semaphore_V(a_mutex_semaphore); //互斥semaphore_V(sem_idBr);//V操作sleep(1);}}/***************************************** A接收B的信息* ***************************************/void *A_Receive(void *arg){int i;for( i=0;i<10;i++ ){semaphore_P(sem_idAr);//P操作semaphore_P(b_mutex_semaphore);//互斥a_buf_top-=1;//A接收B发送邮件,A的邮件数量减一printf("A receive from B:%d\n",a_buf[a_buf_top]);semaphore_V(b_mutex_semaphore); //互斥semaphore_V(sem_idBs);//V操作sleep(1);}}/**************************************** B向A发送信息* ************************************/void *B_Send(void *arg){int i;for(i=0;i<10;i++){semaphore_P(sem_idBs);semaphore_P(b_mutex_semaphore);int number=rand();printf("B send to A:%d\n",number);a_buf[a_buf_top]=number;a_buf_top+=1;semaphore_V(b_mutex_semaphore);semaphore_V(sem_idAr);sleep(1);}}/***************************************** B接收A的信息* ***************************************/void *B_Receive(void *arg){int i;for( i=0;i<10;i++){semaphore_P(sem_idBr);semaphore_P(a_mutex_semaphore);b_buf_top-=1;printf("B receive from A: %d\n",b_buf[b_buf_top]);semaphore_V(a_mutex_semaphore);semaphore_V(sem_idAs);sleep(1);}}int main(){/*创建线程1*/pthread_t thread1;pthread_t thread2;pthread_t thread3;pthread_t thread4;/*创建信号量*/if( (sem_idAs=semget( (key_t)1,1,IPC_CREAT|0660) )==-1 ) return 1;if( (sem_idBs=semget( (key_t)2,1,IPC_CREAT|0660) )==-1 ) return 1;if( (sem_idAr=semget( (key_t)3,1,IPC_CREAT|0660) )==-1 ) return 1;if( (sem_idBr=semget( (key_t)4,1,IPC_CREAT|0660) )==-1 ) return 1;if( (a_mutex_semaphore=semget( (key_t)5,1,IPC_CREAT|0660) )==-1 ) return 1;if( (b_mutex_semaphore=semget( (key_t)6,1,IPC_CREAT|0660) )==-1 ) return 1;/*控制信号队列的运作*/semctl(sem_idAs,0,SETVAL,0);semctl(sem_idBs,0,SETVAL,0);semctl(sem_idAr,0,SETVAL,0);semctl(sem_idBr,0,SETVAL,0);semctl(a_mutex_semaphore,0,SETVAL,1);semctl(b_mutex_semaphore,0,SETVAL,1);//调用四个线程,让四个函数并行运行pthread_create(&thread1, NULL, A_Send, NULL);pthread_create(&thread2, NULL, B_Send, NULL);pthread_create(&thread3, NULL, A_Receive, NULL);pthread_create(&thread4, NULL, B_Receive, NULL);sleep(60);//保证主程序退出之前邮箱操作已经完成return 0;}。