[Linux]共享内存

共享内存是UNIX提供的进程间通信手段中速度最快的一种,也是最快的IPC形式。为什么是最快的呢,因为数据不需要在客户进程和服务器进程之间复制,所以是最快的一种IPC。这是虚存中由多个进程共享的一个公共内存块。
两个不同进程A、B共享内存的意思是,同一块物理内存被映射到进程A、B各自的进程地址空间。进程A可以即时看到进程B对共享内存中数据的更新,反之亦然。
如果服务器进程正在将数据放入到共享存储区,则在它做完这一操作之前,客户进程不应当去取这些数据。通常信号量用于同步共享存储访问。
由于共享内存是通过映射到同一块物理内存后进行的通信,因此肯定需要映射到内存的函数和解除映射的函数,主要有以下几种
#define SHMAT       21//空间映射:把上面打开的内存区域连接到用户的进程空间中  
#define SHMDT       22//解除映射:将共享内存从当前进程中分离  
#define SHMGET      23//创建打开一个内存区域  
#define SHMCTL      24//内存区域的控制:包括初始化和删除内存区域。
注意:共享内存通信本身没有提供同步机制,如果同时被多个进程进行映射和写操作,会导致破坏该内存空间的内容。因此在实际应用过程中,需要通过其他的机制来同步对共享内存的访问。比如信号量。
内核为每个共享存储段维护着一个结构,该结构至少要为每个共享存储段包含以下成员:
struct shmid_ds 
{
    struct ipc_perm shm_perm; //ipc结构体
    size_t shm_segsz;  //请求的size
    pid_t shm_lpid;   //0
    pid_t shm_cpid;   //创建者pid
    shmatt_t shm_nattch; //当前挂载数
    time_t shm_atime;  //0
    time_t shm_dtime; //0
    time_t shm_ctime;  //设置为当前时间
};
1.调用的第一个函数为shmget:
#include<sys/shm.h>
int shmget(key_t key,size_t size,int flag);
//key是创建共享内存id的唯一标识符,size为共享存储段的长度,以字节为单位,通常将其向上取为系统页长的整数倍。如果不是整页,则最后剩余部分是不可用的。flag表示相应的权限位。
2.shmctl函数对共享内存段执行多种操作
#include<sys/shm.h>
int shmctl(int shmid,int cmd,struct shmid_ds *buf);
//IPC_RMID:从系统中删除该共享存储段。
3.一旦创建了共享存储段,进程就可调用shmat将其连接到它的地址空间中。
void *shmat(int shmid,const void* addr,int flag);
//返回若成功,返回指向共享存储段的指针,出错返回-1
//如果成功执行,那么内核将使与该共享存储段相关的shmid_ds结构中的shm_nattch计数器值加1;当对共享存储段的操作已经结束时,则调用shmat与该段分离。这里并没有从系统中删除相关的数据结构,该标识符和ipc数据结构仍然存在。
int shmdt(const void* addr);  //为挂载时的addr
//如果调用成功,则使与该共享存储段相关的shmid_ds结构中的shm_nattch计数器值减1
具体代码实现:
//comm.h
#ifndef _COMM_H_
#define _COMM_H_
#include<stdio.h>
#include<sys/types.h>
#include<sys/ipc.h>
#include<sys/shm.h>

#define PATHNAME "."
#define PROJ_ID 0X6667

int CreateShm(int size);
int GetShm(int size);

int destroyShm(int shmid);






#endif   //_COMM_H_
//comm.c
#include"comm.h"

int CommShm(int size,int flags)
{
    key_t key = ftok(PATHNAME,PROJ_ID);
    if(key < 0)
    {
        perror("ftok");
        return -1;
    }
    int shmid = shmget(key,size,flags); 
    if(shmid < 0)
    {
        perror("shmget");
        return -2;
    }
    return shmid;
}

int CreateShm(int size)
{
    return CommShm(size,IPC_CREAT|IPC_EXCL|0666);
}
int GetShm(int size)
{
    return CommShm(size,IPC_CREAT);
}
int destroyShm(int shmid)
{
    if(shmctl(shmid,IPC_RMID,NULL) < 0)
    {
        perror("shmctl");
        return -1;
    }
    return 0;
}
//server.c
#include"comm.h"

int main()
{
    int shmid = CreateShm(4096);
//  printf("hello server!\n");
    char *addr = shmat(shmid,NULL,0);
    if(addr == NULL)
    {
        return 1;
    }
    int i = 0;
    char s = 'a';
    while(1)
    {
        addr[i] = s;
        s++;
    }
    addr[i] = 0;
    sleep(4);
    shmdt(addr);
    printf("shm quit!\n");
    return 0;
}
//client.c
#include"comm.h"

int main()
{
    int shmid = GetShm(4096);
    //printf("hello client!\n");
    char *addr = shmat(shmid,NULL,0);
    if(addr == NULL)
        return 2;
    printf("%s",addr);

    sleep(10);
    shmdt(addr);    
    printf("shm quit!\n");
    return 0;
}
运行结果:

这里写图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值