c++内存池无锁

使用自己的内存管理方式

最近做监控展示,接收包,解码,播放,多画面短时间轮询,例如10秒,在频繁使用申请内存和删除内存的过程中,不可避免产生性能上的损耗,操作系统在无法申请到内存时,如果自己的程序没有判断申请内存是否成功,后面会产生一系列的问题,最好的解决方案是使用自己的内存管理方式。

定义几个数据结构

enum
{
    
    
    en_emptying = 0,
    en_writing,
    en_canreadings
};
struct smem
{
    
    
    char v_status;
    char v_i_flag;
    char r1;
    char r2;
    int v_len = 0;
    uint32_t v_pts = 0;
    uint8_t *v_data = NULL;
};

typedef std::shared_ptr<smem> ptr_smem;

定义内存池

包含这样的数据指针:
1 数据内存头部
2 数据内存结尾
3 写指针
4 读指针
我们限定只有一个线程读,一个线程写,并且避开读写内存管理的锁定。
我们的数据有两种,一种是数据信息info,也就是我们需要的内存起始,内存长度,以及其他附加数据信息,比如这个包的pts值,这个包的状态信息,是否是关键帧等等,这些东西我们必须要做内存对齐规整,另一种数据就是实际数据,比如h264包,h265包,需要解码的视频数据(或者其他数据)

这其中有两种方式来做这个池,一个是将数据信息直接写入内存的起始位置,一种是将数据信息放入队列,直接放入内存池中也是可以的,这种写法避免了信息队列的维护,当然,信息队列已经是很小的内存了,我们提出两种方式,可以根据需求选择。

方式一,写入内存池

v_write 是内存写入地址,每次写完就往后跳,写入时首先要知道不能超过剩余的空间,否则要等读指针结束,或者让读指针快速通过。写入方法:

   uint8_t *m = v_write;
   *(char*)(m) = (char)en_emptying;
   m +=sizeof(char);
   *(char*)(m) = (char)0;
   m +=sizeof(char)*3;
   *(int*)m = 0;
   m +=sizeof(int);
   *(uint32_t*)m = 0;

以上方法就是将信息数据写入内存池的数据头部,然后再写入数据。这种方式比较考验程序员的基本功,其实也不推荐,另外一种方式直接写入队列中,逻辑清晰,该队列只是一个小型数据集,不会引起性能波动。

以下使用队列和内存池来存放内存

看代码吧,读写指针一定要离开一定的距离,开始时是在一起的,以下代码已经经过验证,当然,在使用的时候还是需要一定的技巧的。

struct s_mem_pool
{
    
    
    //qianbo :just one thread read,one thread write ,otherwise error occur
    uint8_t *v_data = NULL;
    uint8_t *v_end = NULL;
    int v_len = 0;;
    uint8_t *v_write = NULL;
    uint8_t *v_read  = NULL;

    QMutex v_mux;
    std::atomic_int v_framenum;
    std::queue<ptr_smem>v_i;
    void init_mem(int memlen)
    {
    
    
        if(v_data!=NULL)
        {
    
    
            if(v_len < memlen)
            {
    
    
                free(v_data);
                v_data = NULL;
            }
        }


        v_len = memlen;
        if(v_data == NULL)
            v_data = (uint8_t*)malloc(memlen);

        v_end = v_data + memlen;
        v_write = v_data;
        v_read = v_data;
        v_framenum = 0;
        v_mux.lock();
        while(!v_i.empty())
        {
    
    
            v_i.pop();
        }
        v_mux.unlock();



    ~s_mem_pool()
    {
    
    
        clearqueue();
        if(v_data!=NULL)
            free(v_data);
    }


    bool push(uint8_t *data, int len,uint32_t pts,bool i_flag)
    {
    
    
#define EX_LEN (sizeof(char)*4 +sizeof(int)+sizeof(uint32_t))
#define NEEDLEN (len)

#define WRITE_INFO \
        ptr_smem mem = std::make_shared<smem>();\
        mem->v_data = v_write;\
        mem->v_len = len;\
        mem->v_pts = pts;\
        mem->v_i_flag = i_flag; \
        mem->v_status = en_writing;\
        v_mux.lock();\
        v_i.emplace(mem);\
        v_mux.unlock();

#define WRITE_INFO2 \
    uint8_t *m = v_write; \
    *(char*)(m) = (char)en_writing; \
    m +=1; \
    *(char*)(m) = (char)i_flag;\
    m +=3; \
    *(int*)m = len; \
    m +=4; \
    *(uint32_t*)m = pts; \
    m+= 4;\
    v_write = m;


       if(v_write >= v_read)
       {
    
    
           if((v_end - v_write) > (long)(NEEDLEN))
           {
    
    

            memcpy(v_write,data,len);
            WRITE_INFO
             v_write   += (NEEDLEN);
             v_framenum++;
             return true;
           }
           else // the left mem is not enough
           {
    
    
               //qInfo()<<"left mem is not enough";
               if((v_read -v_data) > (long)(NEEDLEN))
               {
    
    
                   v_write = v_data;
                   memcpy(v_write,data,len);
                   WRITE_INFO
                   v_write += NEEDLEN;
                   v_framenum++;
                   return true; //from the head
               }
               else
               {
    
    
                   qInfo()<<"not enough memory 0 :num"<<v_framenum;
                   return false;
               }
           }
       }
       else //read>write
       {
    
    
            if((v_read - v_write) > (long)(NEEDLEN))
            {
    
    
                memcpy(v_write,data,len);
                WRITE_INFO
                v_write += (NEEDLEN);
                v_framenum++;
                //IncNumber();
                return true;
            }
            qInfo()<<"not enough memory 1 clear the buffer the len is "<< NEEDLEN;

            return false;
       }
    }
    ptr_smem get()
    {
    
    
        ptr_smem sm = nullptr;
        v_mux.lock();
        if(!v_i.empty())
        {
    
    
            sm =  v_i.front();
            v_i.pop();
            v_read = sm->v_data;
        }
         v_mux.unlock();
         v_framenum--;
        return sm;

    int size()
    {
    
    
        return v_framenum;
    }
    void clearqueue()
    {
    
    
        v_mux.lock();
        if(!v_i.empty())
        {
    
    
            v_i.pop();
        }
        v_mux.unlock();
    }
};

猜你喜欢

转载自blog.csdn.net/qianbo042311/article/details/121830602