进程间通信-共享内存

共享存储允许两个或多个进程共享一个给定的存储区。因为数据不需要在客户进程和服务器进程之间复制,所以这是最快的一种IPC。使用共享存储时要掌握的唯一窍门是,在多个进程之间同步访问一个给定的存储区。若服务器进程正在将数据放入共享存储区,则在它做完这一操作之前,客户进程不应当去取这些数据。通常,信号量用于同步共享存储访问,也可以用记录锁和互斥量。

System V 共享内存区

调用的第一个函数通常是shmget,它获得一个共享存储标识符

#include<sys/shm.h>
int shmget(key_t key,size_t size,int flag);
返回值:若成功,返回共享存储ID,若失败,返回-1

参数size是该共享存储段的长度,以字节为单位。实现通常将其向上取为系统页长的整数倍。若应用指定的size值并非系统页长的整数倍,那么最后一页的余下部分是不可使用的。如果正在创建一个新段,那么必须指定其size。如果正在引用一个现存的段,则将其size指定 为0。当创建一个新段时,段内的内容初始化为0。

shmctl函数对共享存储段执行多种操作

#incldue<sys/shm.h>
int shmctl(int shmid,int cmd,struct shmid_ds* buf);
返回值:若成功,返回0;若出错,返回-1

IPC_STAT 取此段的shmid_ds结构,并将它存放在buf指向的结构中
IPC_SET 将字段shm_perm.uid、shm_perm.gid、shm_perm.mode 从buf指向的结构复制到与这个共享存储段相关的shmid_ds结构中。
IPC_RMID 从系统中删除该共享存储段。
Linux和Solaris提供了另外两种命令
SHM_LOCK 在内存中对共享存储段加锁,此命令只能有超级用户执行
SHM_UNLOCK 解锁共享存储段,此命令只能由超级用户执行

一旦创建了一个共享存储段,进程就可以调用shmat将其连接到它的地址空间。

#include<sys/shm.h>
void* shmat(int shmid,const void* addr,int flag);
返回值:若成功,返回指向共享存储段的指针;若出错,返回-1

共享存储段连接到调用进程的哪个地址上与addr参数以及flag中是否指定SHM_RND位有关。

如果addr为0,则此段连接到由内核选择的第一个可用地址上。这是推荐的使用方法。
如果addr非0,并且没有指定SHM_RND,则此段连接到addr指定的地址上。
如果 addr 非0, 并且指定了SHM_RND, 则此段连接到 (addr-(addr mod SHMLBA)) 所表示的地址上。SHM_RND 命令的意思是 “取整’. SHMLBA的意思是 “低边界地址倍数”,它总是2的乘方。 该算式是将地址向下取最近1个SHMLBA的倍数.

除非只在一种硬件上运行应用程序(这在当今是不大可能的),否则不应指定共享存储段所连接到的地址。而是应当指定addr为0,以便由系统选择地址。
如果在flag中指定SHM_RDONLY,则以只读方式连接此段,否则以读写方式连接此段。

当对共享存储段的操作已经结束,则调用shmdt与该段分离。注意,这并不从系统中删除其标识符以及其相关的数据结构。该标识符仍然存在,直到某个进程带IPC_RMID命令的调用shmctl特地删除它为止。

#include<sys/shm.h>
int shmdt(const void* addr);
返回值:若成功,返回0;若出错,返回-1

下面是运用共享存储实现进程间通信的例子

//shmwrite.c

#include<stdio.h>
#include<unistd.h>
#include<stdlib.h>
#include<sys/shm.h>
#include<string.h>
#include<errno.h>

#define MAXLEN 1024
int main()
{
    int shmid;
    char buf[MAXLEN];
    int n;
    void* shmaddr;
    int count=0;
    if((shmid=shmget((key_t)1234,MAXLEN,0666|IPC_CREAT))<0)   //创建共享存储区
    {
        fprintf(stderr,"shmget error:[%s]\n",strerror(errno));
        exit(1);
    }

    if((shmaddr=shmat(shmid,0,0))<0)     //将共享存储区连接到地址空间
    {
        fprintf(stderr,"shmat error:[%s]\n",strerror(errno));
        exit(1);
    }
    while(fgets(buf,MAXLEN,stdin)!=NULL)
    {

        memcpy(shmaddr,buf,MAXLEN);     //写入到共享存储区

    }
    shmctl(shmid,IPC_RMID,0);
    exit(0);
}
//shmread.c

#include<stdio.h>
#include<unistd.h>
#include<stdlib.h>
#include<sys/shm.h>
#include<string.h>
#include<errno.h>

#define MAXLEN 1024
int main()
{
    int shmid;
    char buf[MAXLEN];
    int n;
    void* shmaddr;
    if((shmid=shmget((key_t)1234,0,0))<0)    //引用已创建的共享存储区
    {
        fprintf(stderr,"shmget error:[%s]\n",strerror(errno));
        exit(1);
    }

    if((shmaddr=shmat(shmid,0,SHM_RDONLY))<0)   //将共享存储区连接到内存空间
    {
        fprintf(stderr,"shmat error:[%s]\n",strerror(errno));
        exit(1);
    }
    while(1)
    {
        sleep(5);
        memcpy(buf,shmaddr,MAXLEN);    //从共享存储区读取数据
        printf("%s",buf);
    }
    shmdt(shmaddr);
    exit(0);
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值