栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

作业必备:操作系统实验七【生产者消费者实验(二):共享存储区的同步互斥】

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

作业必备:操作系统实验七【生产者消费者实验(二):共享存储区的同步互斥】

目录

前言:

 【实验资料】 

一、什么是共享存储区邏邏邏?

 二、 相关系统调用

1、shmget( ):创建、获得一个共享存储区。

2、shmat( ) :用来将共享内存映射到进程的虚拟地址空间。

3、shmdt( ):把一个共享存储区从指定进程的虚地址空间断开。

4、shmctl( ):共享存储区的控制,对其状态信息进行读取和修改。

正文:

【实验目的】:

【实验内容】:

一、编写程序,实现多进程对共享存储区的同步访问。

二、编写程序,利用信号量机制实现多进程对共享存储区的同步互斥访问。

【实验感想】: 

1、第一题中, 通过循环判断共享存储区状态实现进程间同步时,出现应答延迟的现象?

2、评价以上两种实现进程间同步的方法。


 

前言:

本篇有点小难~懒zhuzhu可自行阅读红体字。在实验前,我们需要先了解一些基本知识~

 【实验资料】 

一、什么是共享存储区邏邏邏?

共享存储区(Share  Memory)是LINUX系统中通信速度最高的一种通信机制。该机制可使若干进程共享主存中的某一个区域,且使该区域出现(映射)在多个进程的虚地址空间中。另一方面,一个进程的虚地址空间中又可连接多个共享存储区,每个共享存储区都有自己的名字。当进程间欲利用共享存储区进行通信时,必须先在主存中建立一共享存储区,然后将它附接到自己的虚地址空间上。此后,进程对该区的访问操作,与对其虚地址空间的其它部分的操作完全相同。进程之间便可通过对共享存储区中数据的读、写来进行直接通信。

可直接理解下图:

 进程A将建立的共享存储区附接到自己的AA’区域,进程B将它附接到自己的BB’区域。

 二、 相关系统调用

1、shmget( ):创建、获得一个共享存储区。

系统调用格式: shmid=shmget(key,size,flag)

参数定义       int  shmget(key_t key, int size,flag);

其中,key是共享存储区的名字;size是其大小(以字节计);flag是用户设置的标志,如IPC_CREAT。

例:shmid=shmget(key,size,(IPC_CREAT|0400))

    创建一个关键字为key,长度为size的共享存储区

2、shmat( ) :用来将共享内存映射到进程的虚拟地址空间。

所有需要访问共享内存的进程,都需要使用该函数将共享内存映射到自己的地址空间,然后就可以方便地对共享区进行访问操作了。

系统调用格式:virtaddr=shmat(shmid,addr,flag)

参数定义   int  *shmat(int shmid, char * addr ,flag);

其中,shmid是共享存储区的标识符;addr用来指定共享内存的映射地址,一般为0,这样系统会用进程中的首个适用地址来映射共享内存;flag规定共享存储区的读、写权限,以及系统是否应对用户规定的地址做舍入操作。其值为SHM_RDONLY时,表示只能读;其值为0时,表示可读、可写;其值为SHM_RND(取整)时,表示操作系统在必要时舍去这个地址。该系统调用的返回值是共享存储区所附接到的进程虚地址viraddr。

3、shmdt( ):把一个共享存储区从指定进程的虚地址空间断开。

当进程不再需要使用共享内存时,需要使用shmdt来断开地址映射,此时共享内存对象并没有被删除,仍然存在直到某个进程调用shmctl的IPC_RMID操作将其删除。

系统调用格式: shmdt(addr)

参数定义   int shmdt(const void *addr);

其中,addr是要断开连接的虚地址,亦即以前由连接的系统调用shmat( )所返回的虚地址。调用成功时,返回0值,调用不成功,返回-1。

4、shmctl( ):共享存储区的控制,对其状态信息进行读取和修改。

系统调用格式:shmctl(shmid,cmd,buf)

参数定义   int  shmctl(int shmid,cmd,struct shmid_ds *buf);

其中,buf是用户缓冲区地址,cmd是操作命令,可分为多种类型:

  1. IPC_STAT:获取共享内存的信息,存放在buf指向的结构中。
  2. IPC_SET:用buf所指向的结构中的数据重置共享内存的shmid_ds结构中的成员shm_perm.uid、shm_perm.gid和shm_perm.mode。
  3. IPC_RMID:从系统中删除共享内存对象。
  4. SHM_LOCK:锁住共享内存段,由超级用户执行,阻止共享内存段被交换到swap中去。
  5. SHM_UNLOCK:解锁共享内存段,由超级用户执行,允许共享内存段被交换到swap中去。

函数执行成功返回0,出错则为-1

正文: 【实验目的】:
  1. 了解和熟悉共享存储机制
  2. 应用PV操作解决进程间的同步互斥问题。
【实验内容】: 一、编写程序,实现多进程对共享存储区的同步访问。

1、参考代码:

通过循环判断共享存储区状态实现进程间同步。

#include  
#include  
#include  
#include  
#include
#include
#include

#define  SHMKEY  75 
int  shmid;   
int  *addr; 

int fatal(char *mes) 
{ 	perror(mes); 
	exit(1); 
} 

void  client( ) 
{  int i; 
addr=shmat(shmid,0,0);            
for (i=4;i>=0;i--) 
  {  
     while (*addr!=-1); 
     printf("(client) sent *addr= %dn",i); 
     *addr=i;
 } 
sleep(1);
exit(0); 
} 
 
void  server( ) 
{ 
 int tmp;
addr=shmat(shmid,0,0);         
do  
 {    
     *addr=-1; 
     while (*addr==-1); 
     tmp=*addr;
     printf("(server) received *addr=%dn",tmp); 
 }while (tmp);  
shmctl(shmid,IPC_RMID,0);      
exit(0); 
} 
int main() 
{ 
    int pid;
    shmid=shmget(SHMKEY,1024,0660|IPC_CREAT);      
   while ((pid=fork( ))==-1); 
   if (!pid) server( ); 
   system("ipcs  -m"); 
   while ((pid=fork( ))==-1); 
   if (!pid) client( ); 
   system("ipcs  -m"); 
   wait(0); 
   system("ipcs  -m"); 
   wait(0); 
   system("ipcs  -m"); 
}

2、运行结果

 

 

二、编写程序,利用信号量机制实现多进程对共享存储区的同步互斥访问。

 1、参考代码:

#include  
#include  
#include  
#include  

#define  SHMKEY  75 

int  shmid;   
struct sembuf p={0,-1,0},
v={0,1,0};


int fatal(char *mes) 
{ 	perror(mes); 
	exit(1); 
}
 
int  senid,recid;   
typedef union semun{
    int val;
    struct semid_ds *buf;
    unsigned short *array;
} semun;

int sem_init(int key,int i)
{
int semid;
semun arg;
if((semid=semget(key,1,0660|IPC_CREAT))<0)
 fatal("sem_init:semget");
arg.val=i;
if(semctl(semid,0,SETVAL,arg)<0)
 fatal("sem_init:semctl");
return semid;
}



void  client( ) 
{  int i,*addr; 
addr=shmat(shmid,0,0);            

for (i=9;i>=0;i--) 
  {  
     semop(senid,&p,1); 
     printf("(client) sent *addr= %dn",i); 
     *addr=i;
     semop(recid,&v,1);         
 } 
sleep(1);
exit(0); 
} 
 
void  server( ) 
{ 
 int tmp,*addr;
addr=shmat(shmid,0,0);         

do  
 {    
     semop(recid,&p,1); 
     tmp=*addr;
     printf("(server) received *addr=%dn",tmp); 
     semop(senid,&v,1); 
 }while (tmp);  
exit(0); 
} 
 
int main() 
{ 
    int pid;
    shmid=shmget(SHMKEY,1024,0660|IPC_CREAT);  
    
 //   mutex=78;
   sen=73;
   rec=74;    
   senid=sem_init(sen,1);
   recid=sem_init(rec,0);
    
    
   while ((pid=fork( ))==-1); 
   if (!pid) server( ); 
   system("ipcs  -m"); 
   system("ipcs  -s"); 
   while ((pid=fork( ))==-1); 
   if (!pid) client( ); 
   system("ipcs  -m"); 
   wait(0); 
   system("ipcs  -m"); 
   wait(0); 
   system("ipcs  -m"); 
   semctl(senid,0,IPC_RMID);
   semctl(recid,0,IPC_RMID);
   shmctl(shmid,IPC_RMID,0);      
}

2、运行结果

【实验感想】: 

1、第一题中, 通过循环判断共享存储区状态实现进程间同步时,出现应答延迟的现象?

linux是基于时间片轮转的调度策略。client模拟生产者,当共享存储区空时放数据,server模拟消费者当共享存储区满时取数据。在运行过程中,发现每当client发送一次数据后,server要等待大约0.1秒才有响应。同样,之后client又需要等待大约0.1秒才发送下一个数据。

2、评价以上两种实现进程间同步的方法。

  答:(1)是建立一个key为75的共享区,先后fork()两个子进程:server和client,两子进程间通过共享存储区进行通信。通过循环判断共享存储区状态实现进程间同步。

 

(2)是增加了两个同步信号量集、sem-p、sem-v函数和存储信号操作的数组来实现server和client两子进程对共享存储区的同步访问。

 

暑期编程PK赛 得CSDN机械键盘等精美礼品!

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/1016165.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号