目录
前言:
【实验资料】
一、什么是共享存储区邏邏邏?
二、 相关系统调用
1、shmget( ):创建、获得一个共享存储区。
2、shmat( ) :用来将共享内存映射到进程的虚拟地址空间。
3、shmdt( ):把一个共享存储区从指定进程的虚地址空间断开。
4、shmctl( ):共享存储区的控制,对其状态信息进行读取和修改。
正文:
【实验目的】:
【实验内容】:
一、编写程序,实现多进程对共享存储区的同步访问。
二、编写程序,利用信号量机制实现多进程对共享存储区的同步互斥访问。
【实验感想】:
1、第一题中, 通过循环判断共享存储区状态实现进程间同步时,出现应答延迟的现象?
2、评价以上两种实现进程间同步的方法。
前言:
【实验资料】 本篇有点小难~懒zhuzhu可自行阅读红体字。在实验前,我们需要先了解一些基本知识~
一、什么是共享存储区邏邏邏?
共享存储区(Share Memory)是LINUX系统中通信速度最高的一种通信机制。该机制可使若干进程共享主存中的某一个区域,且使该区域出现(映射)在多个进程的虚地址空间中。另一方面,一个进程的虚地址空间中又可连接多个共享存储区,每个共享存储区都有自己的名字。当进程间欲利用共享存储区进行通信时,必须先在主存中建立一共享存储区,然后将它附接到自己的虚地址空间上。此后,进程对该区的访问操作,与对其虚地址空间的其它部分的操作完全相同。进程之间便可通过对共享存储区中数据的读、写来进行直接通信。
共享存储区(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是操作命令,可分为多种类型:
- IPC_STAT:获取共享内存的信息,存放在buf指向的结构中。
- IPC_SET:用buf所指向的结构中的数据重置共享内存的shmid_ds结构中的成员shm_perm.uid、shm_perm.gid和shm_perm.mode。
- IPC_RMID:从系统中删除共享内存对象。
- SHM_LOCK:锁住共享内存段,由超级用户执行,阻止共享内存段被交换到swap中去。
- SHM_UNLOCK:解锁共享内存段,由超级用户执行,允许共享内存段被交换到swap中去。
函数执行成功返回0,出错则为-1
正文:
【实验目的】:
- 了解和熟悉共享存储机制
- 应用PV操作解决进程间的同步互斥问题。
【实验内容】:
一、编写程序,实现多进程对共享存储区的同步访问。
系统调用格式: 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的共享存储区
所有需要访问共享内存的进程,都需要使用该函数将共享内存映射到自己的地址空间,然后就可以方便地对共享区进行访问操作了。
系统调用格式: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是操作命令,可分为多种类型:
- IPC_STAT:获取共享内存的信息,存放在buf指向的结构中。
- IPC_SET:用buf所指向的结构中的数据重置共享内存的shmid_ds结构中的成员shm_perm.uid、shm_perm.gid和shm_perm.mode。
- IPC_RMID:从系统中删除共享内存对象。
- SHM_LOCK:锁住共享内存段,由超级用户执行,阻止共享内存段被交换到swap中去。
- SHM_UNLOCK:解锁共享内存段,由超级用户执行,允许共享内存段被交换到swap中去。
函数执行成功返回0,出错则为-1
正文:
【实验目的】:
- 了解和熟悉共享存储机制
- 应用PV操作解决进程间的同步互斥问题。
【实验内容】:
一、编写程序,实现多进程对共享存储区的同步访问。
当进程不再需要使用共享内存时,需要使用shmdt来断开地址映射,此时共享内存对象并没有被删除,仍然存在直到某个进程调用shmctl的IPC_RMID操作将其删除。
系统调用格式: shmdt(addr)
参数定义 int shmdt(const void *addr);
其中,addr是要断开连接的虚地址,亦即以前由连接的系统调用shmat( )所返回的虚地址。调用成功时,返回0值,调用不成功,返回-1。
正文: 【实验目的】:系统调用格式:shmctl(shmid,cmd,buf)
参数定义 int shmctl(int shmid,cmd,struct shmid_ds *buf);
其中,buf是用户缓冲区地址,cmd是操作命令,可分为多种类型:
- IPC_STAT:获取共享内存的信息,存放在buf指向的结构中。
- IPC_SET:用buf所指向的结构中的数据重置共享内存的shmid_ds结构中的成员shm_perm.uid、shm_perm.gid和shm_perm.mode。
- IPC_RMID:从系统中删除共享内存对象。
- SHM_LOCK:锁住共享内存段,由超级用户执行,阻止共享内存段被交换到swap中去。
- SHM_UNLOCK:解锁共享内存段,由超级用户执行,允许共享内存段被交换到swap中去。
函数执行成功返回0,出错则为-1
【实验内容】: 一、编写程序,实现多进程对共享存储区的同步访问。
- 了解和熟悉共享存储机制
- 应用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两子进程对共享存储区的同步访问。
linux是基于时间片轮转的调度策略。client模拟生产者,当共享存储区空时放数据,server模拟消费者当共享存储区满时取数据。在运行过程中,发现每当client发送一次数据后,server要等待大约0.1秒才有响应。同样,之后client又需要等待大约0.1秒才发送下一个数据。
答:(1)是建立一个key为75的共享区,先后fork()两个子进程:server和client,两子进程间通过共享存储区进行通信。通过循环判断共享存储区状态实现进程间同步。
(2)是增加了两个同步信号量集、sem-p、sem-v函数和存储信号操作的数组来实现server和client两子进程对共享存储区的同步访问。
暑期编程PK赛 得CSDN机械键盘等精美礼品!



