线程实现邮箱通信实验报告.docx
《线程实现邮箱通信实验报告.docx》由会员分享,可在线阅读,更多相关《线程实现邮箱通信实验报告.docx(12页珍藏版)》请在冰豆网上搜索。
![线程实现邮箱通信实验报告.docx](https://file1.bdocx.com/fileroot1/2022-11/30/4fb93585-1b86-4cbd-b58c-b65fbbbf2fd5/4fb93585-1b86-4cbd-b58c-b65fbbbf2fd51.gif)
线程实现邮箱通信实验报告
进程通信实验报告
一、实验名称:
进程通信
二、实验目的:
掌握用邮箱方式进行进程通信的方法,并通过设计实现简单邮箱理解进程通信中的同步问题以及解决该问题的方法。
三、实验原理:
邮箱机制类似于日常使用的信箱。
对于用户而言使用起来比较方便,用户只需使用send()向对方邮箱发邮件receive()从自己邮箱取邮件,send()和receive()的内部操作用户无需关心。
因为邮箱在内存中实现,其空间有大小限制。
其实send()和receive()的内部实现主要还是要解决生产者与消费者问题。
四、实验内容:
进程通信的邮箱方式由操作系统提供形如send()和receive()的系统调用来支持,本实验要求学生首先查找资料了解所选用操作系统平台上用于进程通信的系统调用具体形式,然后使用该系统调用编写程序进行进程间的通信,要求程序运行结果可以直观地体现在界面上。
在此基础上查找所选用操作系统平台上支持信号量机制的系统调用具体形式,运用生产者与消费者模型设计实现一个简单的信箱,该信箱需要有创建、发信、收信、撤销等函数,至少能够支持两个进程互相交换信息,比较自己实现的信箱与操作系统本身提供的信箱,分析两者之间存在的异同。
五、背景知识介绍:
1、sembuf数据结构
structsembuf
{
unsignedshortintsem_num;//semaphorenumber
shortintsem_op;//semaphoreoperation
shortintsem_flg;//operationflag
};
sem_num:
操作信号在信号集中的编号,第一个信号的编号是0。
sem_op:
如果其值为正数,该值会加到现有的信号内含值中。
通常用于释放所控资源的使用权;如果sem_op的值为负数,而其绝对值又大于信号的现值,操作将会阻塞,直到信号值大于或等于sem_op的绝对值。
通常用于获取资源的使用权;如果sem_op的值为0,则操作将暂时阻塞,直到信号的值变为0。
sem_flg:
信号操作标志,可能的选择有两种
IPC_NOWAIT//对信号的操作不能满足时,semop()不会阻塞,并立即返回,同时设定错误信息。
IPC_UNDO//程序结束时(不论正常或不正常),保证信号值会被重设为semop()调用前的值。
这样做的目的在于避免程序在异常情况下结束时未将锁定的资源解锁,造成该资源永远锁定。
2、semop函数
函数原型:
intsemop(intsemid,structsembuf*sops,unsignednsops);
参数说明:
semid:
信号集的识别码,可通过semget获取。
sops:
指向存储信号操作结构的数组指针。
nsops:
信号操作结构的数量,恒大于或等于1。
返回说明:
成功执行时,两个系统调用都返回0。
失败返回-1,错误信息保存在errno中。
3、semget函数
函数原型:
intsemget(key_tkey,intnsems,intsemflg);
参数说明:
key:
关键字值一般是由系统调用ftok()返回的
nsems:
指出了一个新的信号量集中应该创建的信号量的个数
semflg:
打开和存取操作与参数semflg中的内容相关。
返回说明:
如果成功,则返回信号量集的IPC标识符。
如果失败,返回-1,错误信息保存在errno中。
4、semctl函数
函数原型:
intsemctl(intsemid,intsemnum,intcmd,unionsemunarg);
参数说明:
senid:
关键字值
semnum:
信号量数目
cmd:
要操作的具体命令
arg:
semnu的一个联合类型的副本。
返回说明:
返回值:
如果成功,则为一个正数。
如果失败,则为-1。
错误信息保存在errno中。
5、pthread_create函数
函数原型:
intpthread_create(pthread_t*restricttidp,constpthread_attr_t*restrictattr,void*(*start_rtn)(void*),void*restrictarg);
参数说明:
tidp:
指向线程标识符的指针。
attr:
用来设置线程属性。
第三个参数是线程运行函数的起始地址。
arg:
运行函数的参数。
六、设计方案:
1、定义两个数组当作两个邮箱inta_buf[5],b_buf[5];邮箱的容量为5。
2、定义两个指针指向邮箱的顶部inta_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原语操作
**************************************/
intsemaphore_P(intsem_id)
{
structsembufp;
p.sem_num=0;
p.sem_op=-1;
p.sem_flg=SEM_UNDO;
if(semop(sem_id,&p,1)==-1)
{
printf(errno);
return0;
}
return1;
}
/***************************************
*V原语操作
***********************************/
intsemaphore_V(intsem_id)
{
structsembufv;
v.sem_num=0;
v.sem_op=1;
v.sem_flg=SEM_UNDO;
if(semop(sem_id,&v,1)==-1)
{
printf(errno);
return0;
}
return1;
}
/***************************************
*A向B发送信息
*************************************/
void*A_Send(void*arg)
{
inti;
for(i=0;i<10;i++)
{
semaphore_P(sem_idAs);//P操作
semaphore_P(a_mutex_semaphore);//互斥
intnumber=rand();//随机数为发送的邮件
printf("AsendtoB:
%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-lpthreadsemaphore.c
十、实际的实验结果:
ada@ada-desktop:
~/OS$gcc-w-osemaphore-lpthreadsemaphore.c
ada@ada-desktop:
~/OS$./semaphore
BsendtoA:
1804289383
AreceivefromB:
1804289383
AsendtoB:
846930886
BreceivefromA:
846930886
BsendtoA:
1681692777
AreceivefromB:
1681692777
AsendtoB:
1714636915
BreceivefromA:
1714636915
BsendtoA:
1957747793
AreceivefromB:
1957747793
AsendtoB:
424238335
BreceivefromA:
424238335
BsendtoA:
719885386
AreceivefromB:
719885386
AsendtoB:
1649760492
BreceivefromA:
1649760492
BsendtoA:
596516649
AreceivefromB:
596516649
AsendtoB:
1189641421
BreceivefromA:
1189641421
BsendtoA:
1025202362
AreceivefromB:
1025202362
AsendtoB:
1350490027
BreceivefromA:
1350490027
BsendtoA:
783368690
AreceivefromB:
783368690
AsendtoB:
1102520059
BreceivefromA:
1102520059
BsendtoA:
2044897763
AreceivefromB:
2044897763
AsendtoB:
1967513926
BreceivefromA:
1967513926
BsendtoA:
1365180540
AreceivefromB:
1365180540
AsendtoB:
1540383426
BreceivefromA:
1540383426
BsendtoA:
304089172
AreceivefromB:
304089172
AsendtoB:
1303455736
BreceivefromA:
1303455736
ada@ada-desktop:
~/OS$
十一、实验结果分析:
四个线程并发运行,A_Send()和B_Send()发出信息,同时打印出发出的信息内容;A_Receive()和B_Receive()分别接收B_Send()和A_Send()发出的信息,并打印出接受的信息内容。
发出的内容和接收的内容一样,符合时间情况。
十二、附代码
#include
#include
#include
#include
#include
#include
#include
#include
#include
inta_buf[5],b_buf[5];//邮箱的容量为5
inta_buf_top=0,b_buf_top=0;//假设初始时邮箱都为空
intsem_idAs,sem_idBs;//例如sem_idAs代表A此时最多可以向B发送的邮件数
intsem_idAr,sem_idBr;//例如sem_idAr代表A此时邮箱中受到的邮件数
inta_mutex_semaphore,b_mutex_semaphore;//互斥信号量
/****************************************
*P原语操作
**************************************/
intsemaphore_P(intsem_id)
{
structsembufp;
p.sem_num=0;
p.sem_op=-1;
p.sem_flg=SEM_UNDO;
if(semop(sem_id,&p,1)==-1)
{
printf(errno);
return0;
}
return1;
}
/***************************************
*V原语操作
***********************************/
intsemaphore_V(intsem_id)
{
structsembufv;
v.sem_num=0;
v.sem_op=1;
v.sem_flg=SEM_UNDO;
if(semop(sem_id,&v,1)==-1)
{
printf(errno);
return0;
}
return1;
}
/***************************************
*A向B发送信息
*************************************/
void*A_Send(void*arg)
{
inti;
for(i=0;i<10;i++)
{
semaphore_P(sem_idAs);//P操作
semaphore_P(a_mutex_semaphore);//互斥
intnumber=rand();//随机数为发送的邮件
printf("AsendtoB:
%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)
{
inti;
for(i=0;i<10;i++)
{
semaphore_P(sem_idAr);//P操作
semaphore_P(b_mutex_semaphore);//互斥
a_buf_top-=1;//A接收B发送邮件,A的邮件数量减一
printf("AreceivefromB:
%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)
{
inti;
for(i=0;i<10;i++)
{
semaphore_P(sem_idBs);
semaphore_P(b_mutex_semaphore);
intnumber=rand();
printf("BsendtoA:
%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)
{
inti;
for(i=0;i<10;i++)
{
semaphore_P(sem_idBr);
semaphore_P(a_mutex_semaphore);
b_buf_top-=1;
printf("BreceivefromA:
%d\n",b_buf[b_buf_top]);
semaphore_V(a_mutex_semaphore);
semaphore_V(sem_idAs);
sleep
(1);
}
}
intmain()
{
/*创建线程1*/
pthread_tthread1;
pthread_tthread2;
pthread_tthread3;
pthread_tthread4;
/*创建信号量*/
if((sem_idAs=semget((key_t)1,1,IPC_CREAT|0660))==-1)
return1;
if((sem_idBs=semget((key_t)2,1,IPC_CREAT|0660))==-1)
return1;
if((sem_idAr=semget((key_t)3,1,IPC_CREAT|0660))==-1)
return1;
if((sem_idBr=semget((key_t)4,1,IPC_CREAT|0660))==-1)
return1;
if((a_mutex_semaphore=semget((key_t)5,1,IPC_CREAT|0660))==-1)
return1;
if((b_mutex_semaphore=semget((key_t)6,1,IPC_CREAT|0660))==-1)
return1;
/*控制信号队列的运作*/
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);//保证主程序退出之前邮箱操作已经完成
return0;
}