基于共享内存的双缓存实现
#ifndef __SHM_DOUBLE_BUFFER_H__
#define __SHM_DOUBLE_BUFFER_H__
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/mman.h>
#include <fcntl.h>
#include <stdint.h>
#include <strings.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <list>
using namespace std;
class CShmDoubleBuffer
{
public:
enum EBufferFlag
{
E_INIT = 0,
E_FIRST = 1,
E_SECOND = 2
};
CShmDoubleBuffer()
{
m_err[0] = 0;
m_flag = NULL;
m_size = 0;
bzero(m_buffers, sizeof(m_buffers));
}
~CShmDoubleBuffer()
{
if (m_flag != NULL) {
munmap(m_flag, sizeof(uint32_t));
}
if (m_buffers[0] != NULL) {
munmap(m_buffers[0], m_size);
}
if (m_buffers[1] != NULL) {
munmap(m_buffers[1], m_size);
}
}
int init(const char *flagname, const char *bufname1, const char *bufname2, int size)
{
// check parameters
if (flagname == NULL || bufname1 == NULL || bufname2 == NULL || size < 0) {
snprintf(m_err, sizeof(m_err), "invalid parameters! flagname=%p, "
"bufname1=%p, bufname2=%p, buf size=%d",
flagname, bufname1, bufname2, size);
return -1;
}
// get double buffer flag
m_flag = (uint32_t*)getShm(flagname, sizeof(uint32_t));
if (m_flag == NULL) {
return -1;
}
// get buffer itself
m_buffers[0] = getShm(bufname1, size);
m_buffers[1] = getShm(bufname2, size);
if (m_buffers[0] == NULL || m_buffers[1] == NULL) {
snprintf(m_err, sizeof(m_err), "get buffer failed! buf1=%p, buf2=%p",
m_buffers[0], m_buffers[1]);
return -1;
}
m_size = size;
// init flag
if (*m_flag != E_SECOND) {
*m_flag = E_FIRST;
}
return 0;
}
void* getShm(const char *name, int size)
{
int fd = shm_open(name, O_RDWR | O_CREAT, 0666);
if (fd < 0) {
snprintf(m_err, sizeof(m_err), "shm_open failed! name=%s, errno=%d", name, errno);
return NULL;
}
int ret = ftruncate(fd, size);
if (ret < 0) {
snprintf(m_err, sizeof(m_err), "ftruncate failed! fd=%d, errno=%d", fd, errno);
return NULL;
}
void *addr = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
if (addr == NULL) {
snprintf(m_err, sizeof(m_err), "mmap failed! fd=%d, errno=%d", fd, errno);
}
return addr;
}
inline void* getMaster()
{
if (*m_flag == E_FIRST) {
return m_buffers[0];
}
else if (*m_flag == E_SECOND) {
return m_buffers[1];
}
return NULL;
}
inline void* getSlave()
{
if (*m_flag == E_FIRST) {
return m_buffers[1];
}
else if (*m_flag == E_SECOND) {
return m_buffers[0];
}
return NULL;
}
inline void swap()
{
if (*m_flag == E_FIRST) {
*m_flag = E_SECOND;
}
else if (*m_flag == E_SECOND) {
*m_flag = E_FIRST;
}
}
public:
char m_err[256];
uint32_t *m_flag;
int m_size;
void* m_buffers[2];
};
#endif