new delete 运算符重载之 内存池申请

#include <iostream>
using namespace std;

const int QUEUEITEM_SIZE = 100000;
template<typename T>
class Queue
{
public:
	Queue()
	{
		_prear = _pfirst = new QueueItem();
	}
	~Queue()
	{
		QueueItem  * pcur = _pfirst;
		while (pcur != NULL)
		{
			_pfirst = _pfirst->_pnext;
			delete   pcur;
			pcur = _pfirst;
		}
		delete _pfirst;
	}
	void addQue(const T &val);
	void delQue();
	T top();
	bool empty()const;
	void showQueue();
private:
	class QueueItem
	{
	public:
		QueueItem(T data=T()):_data(data),_pnext(NULL){};
		
		//编译器默认就处理成static函数
		void* operator new(size_t size)
		{
			QueueItem *p = _pfreelist;
			//判断内存池是否存在
			if(_pfreelist == NULL)
			{
				int mysize = QUEUEITEM_SIZE * size;//总的字节数
				_pfreelist = (QueueItem*)new char[mysize];
				//按照链表方式进行连接
				for(p = _pfreelist; p < _pfreelist+QUEUEITEM_SIZE-1; ++p)
				{
					p->_pnext = p+1;//下一个结点
				}
				p->_pnext = NULL;//最后一个结点单独处理,
			}

			_pfreelist = _pfreelist->_pnext;
			return p;//返回已分配出去的结点
		}
		void operator delete(void *ptr)
		{
			if(ptr == NULL)
			{
				return;
			}
			//归还到内存池
			QueueItem *p = (QueueItem *)ptr;
			p->_pnext = _pfreelist;
			_pfreelist = p;
		}

		T _data;
		QueueItem *_pnext;
		static QueueItem *_pfreelist;//静态成员变量必须在类外初始化
	};
	QueueItem *_pfirst;
	QueueItem *_prear;
};

template<typename T>
typename Queue<T>::QueueItem *Queue<T>::QueueItem::_pfreelist = NULL;//嵌套类,加外层类的作用域

template<typename T>
void Queue<T>::addQue(const T& val)
{
	QueueItem *tmp = new QueueItem(val);
	if (_prear == NULL)
	{   
		_prear = tmp;
		_pfirst = tmp;
		return ;
	}
	_prear ->_pnext = tmp;
	_prear = tmp;
}

template<typename T>
void Queue<T>::delQue()
{
	QueueItem *pcur = _pfirst->_pnext;
	if(pcur == NULL)
		return;
	if(pcur->_pnext == NULL)
		_prear = _pfirst;
	_pfirst->_pnext = pcur->_pnext;
	delete pcur;
}

template<typename T>
T  Queue<T>::top()
{
	return _pfirst->_pnext->_data;
}

template<typename T>
bool Queue<T>::empty()const
{
	return _pfirst == _prear;
}


template<typename T>
void Queue<T>::showQueue()
{
	QueueItem *pcur = _pfirst->_pnext;
	while(pcur != NULL)
	{
		cout<<pcur->_data<<" ";
		pcur = pcur->_pnext;
	}
	cout<<endl;
}


int main()
{
	//  100000QueueItem的节点
	Queue<int> intQueue;

	intQueue.addQue(10);
	intQueue.addQue(4);
	intQueue.addQue(67);
	intQueue.addQue(21);
	intQueue.addQue(5);
	intQueue.addQue(9);
	intQueue.addQue(31);

	intQueue.delQue();
	intQueue.delQue();
	intQueue.delQue();
	
	intQueue.showQueue();
	cout<<intQueue.top()<<endl;
	
	return 0;
}


每一个进程里可以有很多个线程,每一个线程不同的就是它们的线程栈寄存器值不一样.

什么是线程栈

一个线程属于一个单独的执行流,开辟线程的时候需要有一个线程函数,函数必须在栈上开辟内存运行,所以开辟一个线程必须先分配一块线程栈。

linux上创建线程:pthread_create(&tid,NULL,threadproc,&data);
第二个参数是线程属性(线程栈大小默认大小为4k 或8k、线程安全属性、线程优先级),没有指定,传默认值。
多个线程轮流占用CPU的时间片,假如线程A在执行过程中将计算结果存入CPU的寄存器中,时间片时间到达,线程B就要占用CPU的时间片,CPU要执行线程B的线程栈中的代码,此时线程A的计算结果就要存在线程A的线程栈中。


多线程共享堆内存,数据段和代码段。

问题:线程之间的调度顺序无法预知,假如多线程访问共享队列对象,添加结点,即queue.addQue(xxx) 的时候是否是线程安全的?
什么是线程安全?是否是线程安全的首先要判断是否存在竞态条件。那么,什么是竞态条件

竞态条件:代码运算的结果,随着CPU调度顺序的不同而不同,就存在竞态条件。

存在竞态条件的代码段叫做临界区。临界区一定要保证原子操作,进行互斥或者同步。

存在竞态条件—》非线程安全函数—》也叫不可重入函数


所以,上边问题的答案是:queue.addQue(xxx) 的时候不是线程安全的,因为operator new ()存在竞态条件。

因此,此次写的内存池只能用于单线程中,不能在多线程中使用。

猜你喜欢

转载自blog.csdn.net/Mk_kkkk/article/details/54019020
今日推荐