c++内存池无锁
Posted qianbo_insist
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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();
;
以上是关于c++内存池无锁的主要内容,如果未能解决你的问题,请参考以下文章