1. ShareMem.h

#ifndef SHARE_MEM_H
#define SHARE_MEM_H

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


class CShareMem{
private:
key_t m_key; //共享内存键值
int m_iShmId; //共享内存ID
void *m_pvAddr; //共享内存的起始地址
int m_iTotalSize; //共享内存总大小
int m_iUsageSize; //共享内存已使用

//描述:共享内存初始化
int ShmInit();

//描述:附加到共享内存指定地址
//返回:成功返回附加的地址,否则为NULL
void *ShmAtt();

//描述:分离到共享内存指定地址
//返回:成功返回0,否则为-1
int ShmDat();

public:
CShareMem(int iTotalSize);

~CShareMem();

//描述:申请共享内存地址
const char *NewShmAddr(int iAddrSize);

//描述:删除共享内存地址
int DelShmAddr();
};

//描述:共享内存初始化
//参数:@iTotalSize 共享内存大小
//返回:成功返回0,反之失败返回-1
int ShmInit(int iTotalSize);

//描述:分配共享内存
//参数:@iAddrSize 请求分配的共享内存大小
//返回:成功返回新内存地址,否则为NULL
const char *NewShmAddr(int iAddrSize);

//描述:释放共享内存
//返回:成功返回0,反之返回-1
int DelShmAddr();

#endif

2. ShareMem.cpp

#include <string.h>
#include "ShareMem.h"


CShareMem::CShareMem(int iTotalSize)
{
m_iTotalSize = iTotalSize;
m_iUsageSize = 0;
m_key = 0x78746B6D; //"系统库映射"缩写字符,xtkm=0x78746B6D
ShmInit();
ShmAtt();
}

CShareMem::~CShareMem()
{
shmdt(m_pvAddr);
}

int CShareMem::ShmInit()
{
//long page_size = sysconf(_SC_PAGESIZE);
//int data_size = (m_iMemTol + page_size - 1) & (~(page_size - 1));

//printf("CShareMem::ShmInit(): System page size=%d, iMemTolSize=%d, Adjust iMemTolSize=%d.\n", page_size, m_iMemTol, page_size);
//m_iMemTol = page_size;

printf("ShmInit: m_iTotalSize(dec)=%d.\n", m_iTotalSize);

if ((m_iShmId=shmget(m_key, m_iTotalSize, IPC_CREAT)) < 0)
{
if ((m_iShmId=shmget(m_key, m_iTotalSize, IPC_CREAT|IPC_EXCL|0666)) < 0)
printf("CShareMem::ShmInit:shmget() %s\n", strerror(m_iShmId));
}

if (m_iShmId > 0)
printf("CShareMem::ShmInit:shmget() key=0x%08x, ShmId=0x%08x\n", m_key, m_iShmId);

return m_iShmId;
}
}

//描述:附加到共享内存指定地址
//返回:成功返回附加的地址,否则为NULL
void *CShareMem::ShmAtt()
{
m_pvAddr = shmat(m_iShmId, NULL, 0);
if (m_pvAddr == NULL)
printf("CShareMem::ShmAtt() m_pvAddr=NULL!\n");
return m_pvAddr;
}

//描述:分离共享内存指定地址
//参数:@pvShmAddr 附加的共享内层地址
//返回:成功返回0,否则为-1
int CShareMem::ShmDat()
{
return shmdt(m_pvAddr);
}
}

const char *CShareMem::NewShmAddr(int iNewSize)
{
const char *pAddr = NULL;

if (m_iUsageSize+iNewSize > m_iTotalSize)
{
printf("NewShmAddr: The length is too large, pAddr=%p, Offset=%d, iNewSize=%d!!!\n", pAddr, m_iUsageSize, iNewSize);
return NULL;
}

pAddr = (char*)m_pvAddr + m_iUsageSize;
printf("NewShmAddr: pAddr=%p, Offset=%d, iNewSize=%d\n", pAddr, m_iUsageSize, iNewSize);
m_iUsageSize += iNewSize;
return pAddr;
}


//描述:删除共享内存地址
int CShareMem::DelShmAddr()
{
return shmctl(m_iShmId, IPC_RMID, 0);
}

//定义共享内存对象
static CShareMem *g_pCSM=NULL;

//描述:共享内存初始化
//参数:@iTotalSize 共享内存大小
//返回:成功返回0,反之失败返回-1
int ShmInit(int iTotalSize)
{
if (g_pCSM == NULL)
{
if ((g_pCSM=new CShareMem(iTotalSize)) == NULL)
return -1;
}
return 0;
}

//描述:分配共享内存
//参数:@iAddrSize 请求分配的共享内存大小
//返回:成功返回新内存地址,否则为NULL
const char *NewShmAddr(int iAddrSize)
{
if (g_pCSM != NULL)
return g_pCSM->NewShmAddr(iAddrSize);
return NULL;
}

//描述:释放共享内存
//返回:成功返回0,反之返回-1
int DelShmAddr()
{
if (g_pCSM != NULL)
{
if (g_pCSM->DelShmAddr() > 0)
{
delete g_pCSM;
return 0;
}
}
return -1;
}

3. main.cpp

#include <string.h>
#include "ShareMem.h"

#define SHARE_MEM_SIZE (20*1024*1024) //20M
#define SHARE_MEM_USAGE (10*1024) //10K

int main(int argc, char *argv[])
{
const char *pvAddr0, *pvAddr1, *pvAddr2;
int iCnt;
int iRdWr;

if (argc != 2)
exit(0);

iRdWr = atoi(argv[1]);
printf("iRdWr = %d.\n", iRdWr);

//1.共享内存初始化
ShmInit(SHARE_MEM_SIZE);

//2.申请共享内存1
pvAddr0 = NewShmAddr(SHARE_MEM_USAGE);
if (pvAddr0 == NULL)
printf("pvAddr0=%p\n", pvAddr0);

//3.申请共享内存2
pvAddr1 = NewShmAddr(SHARE_MEM_USAGE);
if (pvAddr1 == NULL)
printf("pvAddr1=%p\n", pvAddr1);

//4.申请共享内存3
pvAddr2 = NewShmAddr(SHARE_MEM_USAGE);
if (pvAddr2 == NULL)
printf("pvAddr2=%p\n", pvAddr2);

iCnt = 0;
while(1)
{
if (iRdWr == 0)
{
sprintf((char*)pvAddr0, "hello world! iCnt=%d", iCnt++);
printf("Write pvAddr0=%p, %s\n", pvAddr0, pvAddr0);

sprintf((char*)pvAddr1, "hello world! iCnt=%d", iCnt++);
printf("Write pvAddr1=%p, %s\n", pvAddr1, pvAddr1);

sprintf((char*)pvAddr2, "hello world! iCnt=%d", iCnt++);
printf("Write pvAddr2=%p, %s\n", pvAddr2, pvAddr2);

sleep(1); //1s
}
else
{
printf("Read pvAddr0=%p, %s\n", pvAddr0, pvAddr0);

printf("Read pvAddr1=%p, %s\n", pvAddr1, pvAddr1);

printf("Read pvAddr2=%p, %s\n", pvAddr2, pvAddr2);

usleep(500*1000); //500ms
}
}

//4.释放共享内存
DelShmAddr();
}

4. 编译

arm-linux-gnueabi-g++ ShareMem.cpp -o ShareMem

5. 测试

编译的可执行程序ShareMem通过传入不同的参数0(写)或1(读)控制;

进程1(写)

root@NXBB:/mnt/# ./ShareMem 0
iRdWr = 0.
ShmInit: m_iTotalSize(dec)=20971520.
NewShmAddr: pAddr=0xb5887000, Offset=0, iNewSize=10240
NewShmAddr: pAddr=0xb5889800, Offset=10240, iNewSize=10240
NewShmAddr: pAddr=0xb588c000, Offset=20480, iNewSize=10240
Write pvAddr0=0xb5887000, hello world! iCnt=0
Write pvAddr1=0xb5889800, hello world! iCnt=1
Write pvAddr2=0xb588c000, hello world! iCnt=2
Write pvAddr0=0xb5887000, hello world! iCnt=3
Write pvAddr1=0xb5889800, hello world! iCnt=4
Write pvAddr2=0xb588c000, hello world! iCnt=5

进程2(读)

root@NXBB:/mnt/# ./ShareMem 1
iRdWr = 1.
ShmInit: m_iTotalSize(dec)=20971520.
NewShmAddr: pAddr=0xb5832000, Offset=0, iNewSize=10240
NewShmAddr: pAddr=0xb5834800, Offset=10240, iNewSize=10240
NewShmAddr: pAddr=0xb5837000, Offset=20480, iNewSize=10240
Read pvAddr0=0xb5832000, hello world! iCnt=3
Read pvAddr1=0xb5834800, hello world! iCnt=4
Read pvAddr2=0xb5837000, hello world! iCnt=5
Read pvAddr0=0xb5832000, hello world! iCnt=3
Read pvAddr1=0xb5834800, hello world! iCnt=4
Read pvAddr2=0xb5837000, hello world! iCnt=5
Read pvAddr0=0xb5832000, hello world! iCnt=3
Read pvAddr1=0xb5834800, hello world! iCnt=4
Read pvAddr2=0xb5837000, hello world! iCnt=5

进程3(读)

root@NXBB:/mnt/# ./ShareMem 1
iRdWr = 1.
ShmInit: m_iTotalSize(dec)=20971520.
NewShmAddr: pAddr=0xb5832000, Offset=0, iNewSize=10240
NewShmAddr: pAddr=0xb5834800, Offset=10240, iNewSize=10240
NewShmAddr: pAddr=0xb5837000, Offset=20480, iNewSize=10240
Read pvAddr0=0xb5832000, hello world! iCnt=3
Read pvAddr1=0xb5834800, hello world! iCnt=4
Read pvAddr2=0xb5837000, hello world! iCnt=5
Read pvAddr0=0xb5832000, hello world! iCnt=3
Read pvAddr1=0xb5834800, hello world! iCnt=4
Read pvAddr2=0xb5837000, hello world! iCnt=5
Read pvAddr0=0xb5832000, hello world! iCnt=3
Read pvAddr1=0xb5834800, hello world! iCnt=4
Read pvAddr2=0xb5837000, hello world! iCnt=5