willsun888
12/14/2014 - 7:53 AM

基于共享内存的双缓存实现

基于共享内存的双缓存实现

#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