编译环境:Ubuntu16.04 64位
交叉编译工具:arm-hisiv500-linux-gcc
文章目录
- 1. 项目背景
- 2. 涉及的函数
- 3. 头文件JShm.h
- 4. 类的实现
- 5. sample代码
1. 项目背景
最近项目中需要用到共享内存的交互,自己造个轮子吧。
2. 涉及的函数
详细描述可以百度或ubuntu下查询man手册。
共享内存相关:
int shmget(key_t key, size_t size, int shmflg);
void *shmat(int shmid, const void *shmaddr, int shmflg);
int shmctl(int shmid, int cmd, struct shmid_ds *buf);
信号量相关:
int semget(key_t key,int nsems,int semflg);
int semctl(int semid,int semnum,int cmd, /union semun arg/);
semctl是可变参数长度的函数
int semop(int semid, struct sembuf *sops, size_t nsops);
3. 头文件JShm.h
#include <errno.h>
#include <sys/sem.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <string.h>#ifndef __J_SHM__
#define __J_SHM__#ifdef __cplusplus
extern "C" {
#endif
class JShm {
public:JShm(int key, unsigned int size);~JShm();int Write(unsigned char *buf, unsigned int len);int Read(unsigned char *buf, unsigned int len);private:int Init();int UnInit();int SemP();int SemV();static unsigned int IsPower2(unsigned int size); static unsigned int To2N(unsigned int size);
private:key_t m_shmKey;unsigned int m_size; // 共享内存大小unsigned char *m_buffer; // 共享内存地址int m_shmID;int m_semID;
};#ifdef __cplusplus
}
#endif
#endif // __J_SHM__
4. 类的实现
#include "JShm.h"union SemUnion {int val;struct semid_ds *buf;
};struct ShmHead {unsigned int len; // 数据长度unsigned int refresh; // 数据是否被覆盖unsigned int res[2];
};unsigned int JShm::IsPower2(unsigned int size)
{if (size == 0)return 0;return ((size & (size - 1)) == 0);
}unsigned int JShm::To2N(unsigned int size)
{unsigned int i = 1;unsigned int tmp = size;while (size >>= 1){i <<= 1;}return (i < tmp) ? i << 1 : i;
}// 构造时,请务必保证双方的key和size相同
JShm::JShm(int key, unsigned int size)
{m_shmKey = key;unsigned int nSize = IsPower2(size) ? size : To2N(size);;m_size = nSize + sizeof(ShmHead);m_buffer = NULL;m_shmID = -1;m_semID = -1;Init();
}JShm::~JShm()
{UnInit();
}int JShm::Init()
{m_shmID = shmget(m_shmKey, m_size, IPC_CREAT | IPC_EXCL | 0666);if (m_shmID < 0){if (errno != EEXIST){return -1;}m_shmID = shmget(m_shmKey, m_size, IPC_CREAT | 0666);if (m_shmID < 0){m_shmID = shmget(m_shmKey, 0, 0666);if (m_shmID < 0){return -1;}if (shmctl(m_shmID, IPC_RMID, NULL)!= 0){return -1;}m_shmID = shmget(m_shmKey, m_size, IPC_CREAT | IPC_EXCL | 0666);if (m_shmID < 0){return -1;}}}m_buffer = (unsigned char *)shmat(m_shmID, NULL, 0);if (m_buffer == (unsigned char *)-1){return -1;}memset(m_buffer, 0, m_size);m_semID = semget(m_shmKey, 1, 0666 | IPC_CREAT);if (m_semID < 0){return -1;}union SemUnion semUnion;semUnion.val = 1;semctl(m_semID, 0, SETVAL, semUnion);return 0;
}int JShm::UnInit()
{shmdt(m_buffer);m_buffer = NULL;shmctl(m_shmID, IPC_RMID, NULL);m_shmID = -1;semctl(m_semID, 0, IPC_RMID);m_semID = -1;return 0;
}int JShm::SemP()
{// 申请信号,信号量-1sembuf semP;semP.sem_num = 0;semP.sem_op = -1;semP.sem_flg = SEM_UNDO;semop(m_semID, &semP, 1);return 0;
}int JShm::SemV()
{// 释放信号,信号量+1sembuf semV;semV.sem_num = 0;semV.sem_op = 1;semV.sem_flg = SEM_UNDO;semop(m_semID, &semV, 1);return 0;
}// buf:要写入的数据
// len:要写入的数据的长度
// 返回值:>=0表示成功,0成功,1覆盖旧数据,-1表示失败
int JShm::Write(unsigned char *buf, unsigned int len)
{if (m_buffer == NULL || len > m_size)return -1;int ret = 0;SemP();ShmHead *head = (ShmHead *)m_buffer;head->len = len;memcpy(m_buffer + sizeof(ShmHead), buf, len);if (head->refresh)ret = 1;head->refresh = 1;SemV();return ret;
}// buf:读数据的缓冲区
// len:缓冲区的长度
// 返回值:实际读取到的长度,0表示失败
int JShm::Read(unsigned char *buf, unsigned int len)
{if (m_buffer == NULL)return 0;int ret = 0;SemP();ShmHead *head = (ShmHead *)m_buffer;if (len < head->len) {SemV();return 0;}memcpy(buf, m_buffer + sizeof(ShmHead), head->len);head->refresh = 0;ret = head->len;SemV();return ret;
}
5. sample代码
#include <stdio.h>#define SHM_KEY 101
#define SHM_SIZE 1024
int main(int argc, char* argv[])
{if (argc < 2){return -1;}if (argv[1][0] == 'w'){JShm *ShmWrite = new JShm(SHM_KEY, SHM_SIZE);while (true){char writeBuf[128] = {0};fgets(writeBuf, sizeof(writeBuf), stdin);if (writeBuf[0] == 'q'){delete ShmWrite;return 0;}printf("write data:%s\n", writeBuf);ShmWrite->Write((unsigned char *)writeBuf, strlen(writeBuf));}} else if (argv[1][0] == 'r') {JShm *ShmRead = new JShm(SHM_KEY ,SHM_SIZE);while (true) {char writeBuf[128] = {0};fgets(writeBuf, sizeof(writeBuf), stdin);if (writeBuf[0] == 'q'){delete ShmRead;return 0;}unsigned char readBuf[256] = { 0 };int ret = ShmRead->Read(readBuf, 255);printf("read %d data:%s\n", ret, readBuf);}}return 0;
}
编译完成之后,ubuntu下分别执行./a.out w和./a.out r测试。
以上。
转载请注明出处,如有错漏之处,敬请指正。