boost shared_ptr 及C++内存管理的一些总结

先从实际问题开始讨论, 有个视频采集线程,采集到一帧视频数据, 这帧数据要给存储模块(线程)、RTSP模块,RTMP模块使用。 像这样的情况,内存的申请是在采集线程, 但释放就不能是在采集线程了,所以要实现,谁最后使用,谁释放。如图所示:

 

需求明确,但是代码怎么实现呢? 答案是用到智能指针实现!

智能指针又是怎么实现呢? 智能指针使用引用技术实现, 当指针传递时,引用加1,当指针使用结束,引用减1,如果引用数等于0,则析构对象,释放内存 。

 在上面的例子中,采集模块new出来对象,对象的引用计数为1,对象的指针传给存储模块时,引用计数加1;传给RTSP模块时,引用计数加1;传给RTMP模块时,引用计数加1, 如果几个模块都没有使用结束,此时对象的引用计数为4。采集模块使用结束,引用减1;存储模块使用结束,引用减1;RTSP模块使用结束,引用减1;RRTMP模块使用结束,引用减1, 此时引用计数为0, 析构对象,释放内存。

引用计数的智能指针的具体实现请看:

引用计数的智能指针的实现与思考

 

智能指针在boost里有现成的, 也就是shared_ptr。 怎么使用boost:: shared_ptr来实现我们想要的功能呢? 直接看代码可能更容易理解:

 AVData.h

#ifndef AV_DATA__H
#define AV_DATA__H

#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <unistd.h>
#include <boost/shared_ptr.hpp>

typedef enum _AVDataType
{
	AVDataType_Audio = 1,
	AVDataType_Video,
	AVDataType_Both
}AVDataType;

class AVData
{
public:
	AVData();
	AVData(int i);
	~AVData();

	void TestFunc();
	int	 SetAVData(AVDataType type, const char* buffer, const int size);

	char* GetAVData();
	int	  GetAVDataSize();

private:
	char* m_pBuffer;
	int	  m_iBufferSize;

	int	  m_iCount;
};

typedef boost::shared_ptr<AVData> AVDataPtr;

#endif // AV_DATA__H
</pre>AVDataPool.h<p></p><pre name="code" class="cpp">#ifndef AV_DATA_POOL__H
#define AV_DATA_POOL__H

#include "AVData.h"
#include <boost/thread.hpp>

typedef std::list<AVDataPtr> AVDataList;

class AVDataPool
{
public:
	AVDataPool();
	AVDataPool(int max);
	~AVDataPool();

	void PutAVDataPool(AVDataPtr ptr);
	void GetAVDataPool(AVDataPtr &ptr);

	void Flush();

private:
	AVDataList m_List;
	boost::mutex m_Mutex;
	int	  m_iMaxCount;
};

#endif // AV_DATA_POOL__H
</pre>main<pre name="code" class="cpp">#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <unistd.h>
#include <signal.h>

#include <list>
#include <string>
#include <iostream>
#include <boost/shared_ptr.hpp>

#include "AVData.h"
#include "AVDataPool.h"

void my_handler(int sig);
void ThreadStoreVideo(void *p);
void ThreadRtsp(void *p);
void ThreadRtmp(void *p);


int global_value_exit = 0;

class ThreadParams
{
public:
	ThreadParams()
		:m_pAVDataPool(NULL)
	{

	}

	~ThreadParams()
	{
		if (m_pAVDataPool)
		{
			delete m_pAVDataPool;
			m_pAVDataPool = NULL;
		}
	}

	void InitThreadParams(int count)
	{
		m_pAVDataPool = new AVDataPool(count);
	}

public:
	AVDataPool		*m_pAVDataPool;
};

int main(int argc, char* argv[])
{
	printf("shared_ptr test begin\n");

	struct sigaction sigIntHandler; // 接收Ctrl + C 结束
	sigIntHandler.sa_handler = my_handler;
	sigemptyset(&sigIntHandler.sa_mask);
	sigIntHandler.sa_flags = 0;
	sigaction(SIGINT, &sigIntHandler, NULL);

	ThreadParams *store_params = new ThreadParams();
	store_params->InitThreadParams(3);

	ThreadParams *rtsp_params = new ThreadParams();
	rtsp_params->InitThreadParams(4);

	ThreadParams *rtmp_params = new ThreadParams();
	rtmp_params->InitThreadParams(5);

	boost::thread thread_store(ThreadStoreVideo, store_params);
	boost::thread thread_rtsp(ThreadRtsp, rtsp_params);
	boost::thread thread_rtmp(ThreadRtmp, rtmp_params);

	int i = 0;
	char *buffer = (char*)malloc(4096);
	int size;
	char data = 'a';
	while(!global_value_exit)
	{
		if (data > 'z')
		{
			data = 'a';
		}

		AVDataPtr pAVData(new AVData(i++));
		size = 1024 + rand()%1024; // 生成随机数 1024~2048
		memset(buffer, data, size);

		pAVData->SetAVData(AVDataType_Both, buffer, size);

		data++;

		store_params->m_pAVDataPool->PutAVDataPool(pAVData);
		rtsp_params->m_pAVDataPool->PutAVDataPool(pAVData);
		rtmp_params->m_pAVDataPool->PutAVDataPool(pAVData);

		usleep(200000);
	}

	thread_store.join();
	thread_rtsp.join();
	thread_rtmp.join();

	if (buffer)
	{
		free(buffer);
		buffer = NULL;
	}
	return 0;
}

void ThreadStoreVideo(void *p)
{
	ThreadParams *params = (ThreadParams*)p;

	while(!global_value_exit)
	{
		AVDataPtr ptr;
		params->m_pAVDataPool->GetAVDataPool(ptr);

		if (ptr)
		{
			//ptr->TestFunc();
			char *buffer = ptr->GetAVData();
			printf("%s : %c\n", __func__, *buffer);
		}

		usleep(15000);
	}
}

void ThreadRtsp(void *p)
{
	ThreadParams *params = (ThreadParams*)p;

	while(!global_value_exit)
	{
		AVDataPtr ptr;
		params->m_pAVDataPool->GetAVDataPool(ptr);

		if (ptr)
		{
			//ptr->TestFunc();
			char *buffer = ptr->GetAVData();
			printf("%s : %c\n", __func__, *buffer);
		}

		usleep(15000);
	}
}

void ThreadRtmp(void *p)
{
	ThreadParams *params = (ThreadParams*)p;

	while(!global_value_exit)
	{
		AVDataPtr ptr;
		params->m_pAVDataPool->GetAVDataPool(ptr);

		if (ptr)
		{
			//ptr->TestFunc();
			char *buffer = ptr->GetAVData();
			printf("%s : %c\n", __func__, *buffer);
		}

		usleep(15000);
	}
}

void my_handler(int sig)
{
	if (sig == SIGINT)
	{
		printf("Caught signal %d\n", sig);
		global_value_exit = 1;
	}
}

 

以上就是C++内存管理的一种方式, 当然C++内存管理方式多种多样。 还可以在一开始的时候,申请一大块内存,  然后再通过修改 uint8_t *rptr, *wptr来改变读写内存的位置, 来实现数据的写入和读出。如果代码可以参考ffmpeg  libavutil/fifo.c,实现原理如下图所示:

 

哪种实现性能更优呢?  第二种方法看似更好一些, 一次申请了一大块内存, 不用跟系统频繁申请释放内存, 但是别忘了第二种方法要加锁。没做过性能测试, 不知道哪种方法更好些,  目前开发的系统使用的是第一种方法。 欢迎做过比较测试的朋友告诉我哈

 

 

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值