linux的系统的共享内存

一, linux共享内存介绍

共享内存机制

       是允许两个或多个进程(不相关或有亲缘关系)访问同一个逻辑内存的机制。它是共享和传递数据的一种非常有效的方式。不同进程之间共享的内存通常安排为同一段物理内存。

两种常用共享内存方式

1, System V版本的共享内存 shmm
        多个进程直接共享内存
2, 文件映射 mmap
  1. 文件进行频繁读写,将一个普通文件映射到内存中
  2. 将特殊文件进行匿名内存映射,为关联进程提供共享内存空间
  3. 为无关联的进程提供共享内存空间,将一个普通文件映射到内存中

基本操作
查看共享内存
Ipcs
操作共享内存
ipcrm -m
ipcrm:选项需要一个参数 – m
ipcrm: illegal option – ?
usage: ipcrm [ [-q msqid] [-m shmid] [-s semid]
[-Q msgkey] [-M shmkey] [-S semkey] … ]

案例:第1个应用程序读共享内存,第2个应用程序写共享内存;第3个删除共享内存。会出现什么现象。
Linux内核管理共享内存的机制

命令:

ipcs -m

这里写图片描述

二, linux的共享内存的api介绍

1. ftok函数生成key标识符

key_t ftok(const char *pathname,int proj_id)

2. 创建一个共享内存块,返回这个共享内存块的标识符shmid

int shmget(key_t key,size_t size,int shmflg)
参数说明:size - 申请的共享内存的大小,为4k的整数倍;
shmflg - IPC_CREAT 创建新的共享内存,已存在 使用IPC_EXCL

3.挂接共享内存(将进程地址空间挂接到物理空间,可以有多个挂接)

void *shmat(int shmid,const void *shmaddr, int shmflg)
参数说明:shmid - 挂接的共享内存ID.
shmaddr - 一般为0,表示连接到由内核选择的第一个可用地址上
shmflg - 一般为0

4.取消共享内存映射

int shmdt(const void *shmaddr);

5.用于控制共享内存

  int shmctl(int shmid, int cmd, struct shmid_ds *buf);
参数 shmid - 由shmget返回的共享内存标识码
cmd - 将要采取的动作(可取值:IPC_STAT、IPC_SET、IPC_RMID)
   buf - 指向一个保存着共享内存的模式状态和访问权限的数据结构

三, 写一个简单例子

一个写共享内存, 一个读取共享内存

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

struct Conn_stat
{
    int count;
    char ip[64];
};


int main()
{

    void *shm = NULL;

    int shmid = 0, i = 0;
    struct Conn_stat stat = {0,"陈松爱陈丽"};
    //创建共享内存
    shmid = shmget((key_t)1234, sizeof(struct Conn_stat), 0666|IPC_CREAT);
    if(shmid == -1)
    {
        fprintf(stderr, "shmget failed\n");
        exit(1);
    }
    //将共享内存连接到当前进程的地址空间
    shm = shmat(shmid, (void*)0, 0);
    if(shm == (void*)-1)
    {
        fprintf(stderr, "shmat failed\n");
        exit(2);
    }
    printf("Memory attached at %p\n", shm);

    //设置共享内存
    struct Conn_stat *p = (struct Conn_stat*)shm;
    memcpy(p,&stat,sizeof(struct Conn_stat));

    while((i++) < 30)//修改共享内存中写数据
    {
        p->count++;
        sleep(1);
    }

    //把共享内存从当前进程中分离
    if(shmdt(shm) == -1)
    {
        fprintf(stderr, "shmdt failed\n");
        exit(3);
    }

    exit(0);
}

读取共享内存例子

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

struct Conn_stat
{
    int count;
    char ip[64];

};

int main()
{

    void *shm = NULL;//分配的共享内存的原始首地址
    struct Conn_stat *stat = NULL;//指向shm
    int shmid;//共享内存标识符

    //创建共享内存
    shmid = shmget((key_t)1234, sizeof(struct Conn_stat), 0666|IPC_CREAT);
    if(shmid == -1)
    {
        fprintf(stderr, "shmget failed\n");
        exit(0);
    }
    //将共享内存连接到当前进程的地址空间
    shm = shmat(shmid, 0, 0);
    if(shm == (void*)-1)
    {
        fprintf(stderr, "shmat failed\n");
        exit(1);
    }
    printf("\nMemory attached at %p\n", shm);
    //设置共享内存
    stat = (struct Conn_stat*)shm;


    int i = 0;
    while((i++) < 10)
    {

        printf("ip = %s ,count: %d\t\t\n", stat->ip, stat->count);  
        sleep(1);
    }

    //把共享内存从当前进程中分离
    if(shmdt(shm) == -1)
    {
        fprintf(stderr, "shmdt failed\n");
        exit(2);
    }
    //删除共享内存
    if(shmctl(shmid, IPC_RMID, 0) == -1)
    {
        fprintf(stderr, "shmctl(IPC_RMID) failed, reason: %s\n",strerror(errno));
        exit(3);
    }
    exit(0);
}

makefile

.SUFFIXES: .c .o
CC = gcc
SRCS1 = shmwrite.c
SRCS2 = shmread.c
OBJS1 = $(SRCS1:.c = .o)
OBJS2 = $(SRCS2:.c = .o)

EXE1 = shmwrite
EXE2 = shmread
#$(OBJS2)
all: $(OBJS1) $(OBJS2) 
    $(CC) -o $(EXE1) $(OBJS1) -Wall -g
    $(CC) -o $(EXE2) $(OBJS2) -Wall -g
    @echo '^_^ ^_^ 陈丽 ^_^ ^_^'

#模式匹配
%.c%.o:
    $(CC) -Wall -g -o $@ -c $^



#clean 清空二进制文件
clean:
    -rm -f $(OBJS)
    -rm -f core*

这里写图片描述

四, 共享内存的api的设计

// myipc_shm.h
#ifndef _WBM_MY_SHM_H_
#define _WBM_MY_SHM_H_

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#ifdef __cplusplus 
extern "C" {
#endif

//共享内存错误码
#define     MYIPC_OK                0       //正确
#define     MYIPC_ParamErr          301     //输入参数失败
#define     MYIPC_NotEXISTErr       302     //共享内存不存在错误
#define     MYIPC_CreateErr         303     //创建共享内存错误

//创建共享内存 若共享内存不存在,则创建
int IPC_CreatShm(int key, int shmsize, int *shmhdl);

//打开共享内存 若共享内存不存在,返回错误
int IPC_OpenShm(int key, int shmsize, int *shmhdl);

/***********************************************************************
  功能描述:    关联共享内存
  参数说明:    shmhdl   [in]  共享的句柄
                mapaddr [out] 共享内存首地址
  返回值:      返回0函数执行成功;非0返回错误码
************************************************************************/
int IPC_MapShm(int shmhdl, void **mapaddr);

/***********************************************************************
  功能描述:    取消共享内存关联
  参数说明:    unmapaddr   [in] 共享内存首地址
  返回值:      返回0函数执行成功;非0返回错误码
************************************************************************/
int IPC_UnMapShm(void *unmapaddr);

/***********************************************************************
  功能描述:    删除共享内存
  参数说明:    shmhdl   [in]  共享的句柄
  返回值:      返回0函数执行成功;非0返回错误码
************************************************************************/
int IPC_DelShm(int shmhdl);

/***********************************************************************
  功能描述:    创建共享内存 通过种子文件
  参数说明:    shmname  [in]  是共享内存名,系统中唯一标志
                shmsize  [in]  是要创建的共享内存的大小;
                shmhdl   [out] 共享内存的句柄.
  返回值:      返回0函数执行成功;非0返回错误码
************************************************************************/
int IPC_CreatShmBySeedName(const char *shmname, int shmsize, int *shmhdl);

#ifdef __cplusplus
}
#endif
#endif

实现

#define _OS_LINUX_

#if defined _OS_LINUX_
#include <stdio.h>
#include <errno.h>
#include <unistd.h>
#include <memory.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/sem.h>
#include <sys/msg.h>
#include "myipc_shm.h" 

#endif

int shmflag = 0;
int shmkey;


//创建共享内存 若共享内存不存在,则创建 若存在使用原来的
int IPC_CreatShm(int key, int shmsize, int *shmhdl)
{
    int     tmpshmhdl = 0;
    int     ret = 0;
     // 创建共享内存 
     // 若共享内存不存在则创建 
     // 若共享内存已存在使用原来的
    tmpshmhdl = shmget(key, shmsize, IPC_CREAT|0666);
    if (tmpshmhdl == -1)            //创建失败
    {
        ret = MYIPC_ParamErr;
        printf("func shmget() err :%d ", ret);
        return ret;
    }
    *shmhdl = tmpshmhdl;
    return ret;
}

//打开共享内存 若共享内存不存在,返回错误
//参数 无意义 可填写0
int IPC_OpenShm(int key, int shmsize, int *shmhdl)
{
    int     tmpshmhdl = 0;
    int     ret = 0;
     // 创建共享内存 
     // 若共享内存不存在则创建 
     // 若共享内存已存在使用原来的
    tmpshmhdl = shmget(key, 0, 0);
    if (tmpshmhdl == -1)            //打开失败
    {
        ret = MYIPC_NotEXISTErr;
        //printf("func shmget() err :%d ", ret);
        return ret;
    }
    *shmhdl = tmpshmhdl;
    return ret;

}

/***********************************************************************
  功能描述:    创建共享内存
  参数说明:    shmname  [in]  是共享内存名,系统中唯一标志
                shmsize  [in]  是要创建的共享内存的大小;
                shmhdl   [out] 共享内存的句柄.
  返回值:      返回0函数执行成功;非0返回错误码
************************************************************************/
int IPC_CreatShmBySeedName(const char *shmseedfile, int shmsize, int *shmhdl)
{
    if(shmflag == 0)            //判断接口中共享内存key是否已经存在
    {
        shmkey = ftok(shmseedfile, 'c');
        if (shmkey == -1)
        {
            perror("ftok");
            return -1;
        }

        shmflag = 1;
    }

    //创建共享内存
    *shmhdl = shmget(shmkey,shmsize,IPC_CREAT|0666);
    if (*shmhdl == -1)          //创建失败
        return -2;
    return 0;

}
/***********************************************************************
  功能描述:    关联共享内存
  参数说明:    shmhdl   [in]  共享的句柄
                mapaddr [out] 共享内存首地址
  返回值:      返回0函数执行成功;非0返回错误码
************************************************************************/
int
IPC_MapShm(int  shmhdl, void **mapaddr)
{
    void *tempptr = NULL;

    //连接共享内存
    tempptr = (void *)shmat(shmhdl,0,SHM_RND);
    if ((int)tempptr == -1)     //共享内存连接失败
        return -1;
    *mapaddr = tempptr;         //导出共享内存首指针

    return 0;
}
/***********************************************************************
  功能描述:    取消共享内存关联
  参数说明:    unmapaddr   [in] 共享内存首地址
  返回值:      返回0函数执行成功;非0返回错误码
************************************************************************/
int IPC_UnMapShm(void *unmapaddr)
{
    int  rv;
    //取消连接共享内存 
    rv = shmdt((char *)unmapaddr);
    if (rv == -1)           //取消连接失败
        return -1;

    return 0;
}
/***********************************************************************
  功能描述:    删除共享内存
  参数说明:    shmhdl   [in]  共享的句柄
  返回值:      返回0函数执行成功;非0返回错误码
************************************************************************/
int IPC_DelShm(int shmhdl)
{
    int  rv;
    //删除共享内存
    rv = shmctl(shmhdl,IPC_RMID,NULL);
    if(rv < 0)              //删除共享内存失败
        return -1;

    return 0;
}

五, mmap共享文件映射

   void *mmap(void *addr, size_t length, int prot, int flags,
              int fd, off_t offset);
   int munmap(void *addr, size_t length); 

参数start:指向欲映射的内存起始地址,通常设为 NULL,代表让系统自动选
定地址,映射成功后返回该地址。

参数length:代表将文件中多大的部分映射到内存。

参数prot:映射区域的保护方式。可以为以下几种方式的组合:

       PROT_EXEC         执行   
       PROT_READ         读取
                  PROT_WRITE      写入
      PROT_NONE       不能存取
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<fcntl.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<sys/mman.h>
#include<string.h>

struct Conn_stat
{
    int count;
    char ip[64];

};


int main(int argc,char *argv[]) //这个进程用于创建映射区进行写。
{
    if(argc != 2)
    {
        printf("Usage: %s  file.\n",argv[0]);
        exit(1);
    }

    struct Conn_stat stat = {0,"陈松爱陈丽 --- 杨艳"};

    int fd = open(argv[1],O_RDWR|O_CREAT|O_TRUNC,0644);
    if(fd < 0)
    {
        perror("open");
        exit(2);
    }
    ftruncate(fd,sizeof(struct Conn_stat)); 

    struct Conn_stat *p = (struct Conn_stat*)mmap(NULL,sizeof(struct Conn_stat),PROT_READ|PROT_WRITE,MAP_SHARED,fd,0);//创建一个结构体大小的共享映射区。共享映射区我们可以当做数组区看待。
    if(p == MAP_FAILED)
    {
        perror("mmap");
        exit(3);
    }
    close(fd); //关闭不用的文件描述符。

    memcpy(p,&stat,sizeof(struct Conn_stat));

    while(1)
    {

        p->count++;
        sleep(1);
    }
    int ret = munmap(p,sizeof(struct Conn_stat));
    if(ret < 0)
    {
        perror("mmumap");
        exit(4);
    }

    return 0;
}

#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<fcntl.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<sys/mman.h>

struct Conn_stat
{
    int count;
    char ip[64];
};

int main(int argc,char *argv[]) //这个进程创建映射区进行读
{
    if(argc != 2)
    {
        printf("Usage: %s  file.\n",argv[0]);
        exit(1);
    }


    int fd = open(argv[1],O_RDONLY,0644);
    if(fd < 0)
    {
        perror("open");
        exit(2);
    }

    struct Conn_stat stat;

    struct Conn_stat *p = (struct Conn_stat*)mmap(NULL,sizeof(struct Conn_stat),PROT_READ,MAP_SHARED,fd,0);
    if(p == MAP_FAILED)
    {
        perror("mmap");
        exit(3);
    }
    close(fd);

    int i = 0;
    while((i++) < 10)
    {

        printf("ip = %s ,count: %d\t\t\n",p->ip,p->count);  
        sleep(1);
    }
    int ret = munmap(p,sizeof(stat));
    if(ret < 0)
    {
        perror("mmumap");
        exit(4);
    }

    return 0;
}

这里写图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值