目录

  • 前期基础知识

  • 客户端向服务器端共享存储区

  • 子进程之间共享存储区



  • 前期基础知识

    本次实验其实重点的是这么几个变量:addr、shmid 以及几个重要的函数:shmet、shmat、shmget、shmctl

对于系统V共享内存,主要有以下几个API:shmget()、shmat()、shmdt()及shmctl()。

   #include<sys/ipc.h>

   #include<sys/shm.h>

   shmget()用来获得共享内存区域的ID,如果不存在指定的共享区域就创建相应的区域。shmat()把共享内存区域映射到调用进程的地址空间中去,这样,进程就可以方便地对共享区域进行访问操作。shmdt()调用用来解除进程对共享内存区域的映射。shmctl实现对共享内存区域的控制操作。

注:shmget的内部实现包含了许多重要的系统V共享内存机制;shmat在把共享内存区域映射到进程空间时,并不真正改变进程的页表。当进程第一次访问内存映射区域访问时,会因为没有物理页表的分配而导致一个缺页异常,然后内核会根据相应的存储管理机制为共享内存映射区域分配相应的页表。

    应当指出,共享存储区机制只为进程提供了用于实现通信的共享存储区和对共享存储区进行操作的手段,然而并未提供对该区进行互斥访问及进程同步的措施。因而当用户需要使用该机制时,必须自己设置同步和互斥措施才能保证实现正确的通信。

涉及的系统调用

1、shmget( )

创建、获得一个共享存储区。

系统调用格式:

        shmid=shmget(key,size,flag)

该函数使用头文件如下:

#include<sys/types.h>

#include<sys/ipc.h>

#include<sys/shm.h>

参数定义

         int  shmget(key,size,flag);

         key_t  key;

         int  size,flag;

其中,key是共享存储区的名字;size是其大小(以字节计);flag是用户设置的标志,如IPC_CREAT。IPC_CREAT表示若系统中尚无指名的共享存储区,则由核心建立一个共享存储区;若系统中已有共享存储区,便忽略IPC_CREAT。

附:

        操作允许权                  八进制数

         用户可读                     00400

         用户可写                     00200

         小组可读                     00040

         小组可写                     00020

         其它可读                     00004

         其它可写                     00002

        

控制命令                    值

IPC_CREAT                0001000

IPC_EXCL                0002000

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

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

2、shmat( )

    共享存储区的附接。从逻辑上将一个共享存储区附接到进程的虚拟地址空间上。

系统调用格式:

                virtaddr=shmat(shmid,addr,flag)

该函数使用头文件如下:

#include<sys/types.h>

#include<sys/ipc.h>

#include<sys/shm.h>

参数定义

         char  *shmat(shmid,addr,flag);

         int  shmid,flag;

         char  * addr;

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

3、shmdt( )

把一个共享存储区从指定进程的虚地址空间断开。

系统调用格式:

             shmdt(addr)

该函数使用头文件如下:

#include<sys/types.h>

#include<sys/ipc.h>

#include<sys/shm.h>

参数定义

         int  shmdt(addr);

         char  addr;

其中,addr是要断开连接的虚地址,亦即以前由连接的系统调用shmat( )所返回的虚地址。调用成功时,返回0值,调用不成功,返回-1。 值得注意的是: 这里的addr我们可以用于存数据

4、shmctl( )

共享存储区的控制,对其状态信息进行读取和修改。

系统调用格式:

              shmctl(shmid,cmd,buf)

该函数使用头文件如下:

#include<sys/types.h>

#include<sys/ipc.h>

#include<sys/shm.h>

参数定义

             int  shmctl(shmid,cmd,buf);

             int shmid,cmd;

             struct shmid_ds  *buf;

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

(1)用于查询有关共享存储区的情况。如其长度、当前连接的进程数、共享区的创建者标识符等;

(2)用于设置或改变共享存储区的属性。如共享存储区的许可权、当前连接的进程计数等;

(3)对共享存储区的加锁和解锁命令;

(4)删除共享存储区标识符等。

    上述的查询是将shmid所指示的数据结构中的有关成员,放入所指示的缓冲区中;而设置是用由buf所指示的缓冲区内容来设置由shmid所指示的数据结构中的相应成员。

cmd有下列几种数值:

IPC_STAT         把共享内存的

IPC_SET          将参数buf所指的shmid_ds 结构中的shm_perm.uid、shm_perm.gid和shm_perm.mode复制到共享内存的shmid_ds结构内。

IPC_RMID         删除共享内存和数据结构。

SHM_LOCK       不让此共享内存置换到swap。

SHM_UNLOCK    允许此gon共享内存置换到swap。

SHM_LOCK 和SHM_UNLOCK为LUNIX特有,且唯有超级用户(root)允许使用




  • 客户端向服务器端共享存储区

为了方便调试我还是觉得直接将客户端与服务器端作为了函数进行了调用,这位我们第三个实验简化了步骤

#include <sys/types.h>
#include <sys/shm.h>
#include <sys/ipc.h>
#define  SHMKEY  75
int  shmid,i;   int  *addr;

void  client( )
{  int i=0;
       shmid=shmget(SHMKEY,1024,0777);      /*打开共享存储区*/
addr=shmat(shmid,0,0);           /*获得共享存储区首地址*/
for (i=9;i>=0;i--)
  {  while (*addr!=-1);
     printf("(client) sent\n");
     *addr=i;
 }
exit(0);
}

void  server( )
{
shmid=shmget(SHMKEY,1024,0777|IPC_CREAT); /*创建共享存储区*/
addr=shmat(shmid,0,0);        /*获取首地址*/
do 
 {
     *addr=-1;
     while (*addr==-1);
     printf("(server) received\n");
}while (*addr);
shmctl(shmid,IPC_RMID,0);     /*撤消共享存储区,归还资源*/
exit(0);
}

main( )
{
   while ((i=fork( ))==-1);
   if (!i) server( );
   while ((i=fork( ))==-1);
   if (!i) client( );
   wait(0);
   wait(0);
}



 

  • 子进程之间共享存储区


#include <sys/types.h>
#include <sys/shm.h>
#include <sys/ipc.h>
#define  SHMKEY  75
int  shmid,i;   int  *addr;


void  shmw( )
{  int i=0;
       shmid=shmget(SHMKEY,1024,0777);      /*打开共享存储区*/
addr=shmat(shmid,0,0);           /*获得共享存储区首地址*/
for (i=9;i>=0;i--)
  {  while (*addr!=-1);
     printf("(write) is  \n");
     *addr=i;
 }
exit(0);
}


void  shmr( )
{
shmid=shmget(SHMKEY,1024,0777|IPC_CREAT); /*创建共享存储区*/
addr=shmat(shmid,0,0);        /*获取首地址*/
do 
 {
     *addr=-1;
     while (*addr==-1);
     printf("(read) ok is ");
     printf("%d\n",*addr);
}while (*addr);
shmctl(shmid,IPC_RMID,0);     /*撤消共享存储区,归还资源*/
exit(0);
}

main( )
{
   while ((i=fork( ))==-1);
   if (!i) shmr( );
   while ((i=fork( ))==-1);
   if (!i) shmw( );
   wait(0);
   wait(0);
}

Logo

更多推荐