#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 ()存在竞态条件。
因此,此次写的内存池只能用于单线程中,不能在多线程中使用。