现在的位置: 首页 > 综合 > 正文

windows内存池 一线程分配 一线程释放 无锁 安全?

2013年10月09日 ⁄ 综合 ⁄ 共 3651字 ⁄ 字号 评论关闭

lock-free这种东西,我只要想想就能感到其复杂程度超出我的想象,但是呢,它又的的确确是好东西,于是就起了收集一套源码的念头(估计多数伸手党也就是这么产生的),还算幸运,找到一个库,简单测试一下,各种lock-free,各种高效。

 

好吧,打住,今天主打内存池。

 

写内存池的想法来自CSDN的一位博主,他的一篇文章:一度一写情况下,无锁队列如何实现,直接贴上链接:http://blog.csdn.net/kyee/article/details/4032596

 

博友dfasri 也对这篇文章所阐述的观点给与了某种意义上的肯定,至少肯定那种算法的正确性。像我这种低端伸手党很自然的就肯定那种无锁队列是可行的了。最主要的还是dfasri在回复中提到了内存池,于是我就想,反正内存池的设计也是可以基于队列的,既然一读一写情况下,队列可以无锁,那么依照此观点,设计一个一线程分配,一线程释放的无锁内存池也差不多可行吧?

 

仔细想想,如果这种内存池造出来的话,作用虽然不大,但也不是完全没有作用。熟悉IOCP的童鞋都应该知道,工作线程收到数据包后,往往是通过队列将数据交给处理线程的,如果队列是无锁的,内存分配也是无锁的,甚至队列内部的内存分配也是无锁的,那效果应该还可以吧,尤其在一个工作线程对应一个数据处理线程的情况下,效果应该更好吧,我猜的。

 

嗯,那就试试吧。

 

免责申明:代码写得非常难看(不是因为写得仓促,完全是由于本人脑袋非常不灵光,加上不思进取,不懂得经常性的自我充电,所以水平实在太烂),不保证代码的安全性,前面已经说了,这份代码全由两位博友引发,本人只是照葫芦画瓢而已,追求也没有下限,看得不爽,请多见谅。

 

MPool_C语言版:

 

#include <malloc.h>

typedef unsigned long uLong;
typedef unsigned long *** HMP1;

struct MN1
{
	uLong uFlag; uLong uResv; MN1 *next;
};

struct MP1
{
	MN1 *pStart; MN1 *pClose; uLong uSize;
};

void  Mp1_Delete(HMP1 hMp1){}

HMP1 Mp1_Create(uLong uSize,uLong uCount)
{
	MP1 *m=(MP1*)::malloc(sizeof(MP1)); m->uSize=uSize+sizeof(MN1); MN1 *n=(MN1*)::malloc(m->uSize);
	m->pStart=n;
	for(uLong i=0;i<uCount;i++)
	{
		n->uFlag=0; n->uResv=(uLong)m; if(i==uCount-1){n->next=0; break;}
		n->next=(MN1*)::malloc(m->uSize); n=n->next;
	}m->pClose=n; return (HMP1)m;
}

void *Mp1_Malloc(HMP1 hMp1)
{
	MP1 *m=(MP1*)hMp1; uLong u=sizeof(MN1); MN1 *n=m->pStart; MN1 *h=n->next;
	if(h==0)
	{
		n=(MN1*)::malloc(m->uSize); n->uResv=0; return (char*)n+u;
	}n->uFlag=1; m->pStart=h; return (char*)n+u;
}

void Mp1_Free(void *pArg)
{
	uLong u=sizeof(MN1); MN1 *n=(MN1*)((uLong)pArg-u); MP1 *m=(MP1*)n->uResv;
	if(m==0)
	{
		::free((char*)pArg-u); return; //::free(pArg); return;
	}	
	if(n->uFlag==0) return; n->uFlag=0; n->next=0; m->pClose->next=n; m->pClose=n;
}

 MPool_C++版本:

//TMPool.h
#if !defined(AFX_TMPOOL_H__099C42CF_00CC_495E_944F_7C42E4F0BC44__INCLUDED_)
#define AFX_TMPOOL_H__099C42CF_00CC_495E_944F_7C42E4F0BC44__INCLUDED_

#if _MSC_VER > 1000
#pragma once
#endif

struct MPNODE
{
	unsigned long flag;
	unsigned long resv; MPNODE *next;
};

class TMPool  
{
public:
	static void StaticFree(void *arg);
	void Free(void *data);
	void init(unsigned long size,unsigned long count);
	void* Malloc();
	TMPool(); virtual ~TMPool();

private:
	MPNODE* m_tail;
	MPNODE* m_head;
	unsigned long m_size;
};

#endif

 

#include "TMPool.h"
#include <malloc.h>

TMPool::TMPool(){}
TMPool::~TMPool(){}

void TMPool::init(unsigned long size,unsigned long count)
{
	m_size=size+sizeof(MPNODE);
	MPNODE *node=(MPNODE*)::malloc(m_size); m_head=node;
	for(unsigned long i=0;i<count;i++)
	{
		node->flag=0; node->resv=(unsigned long)this;
		
		if(i==count-1)
		{
			node->next=0; break;
		}
		node->next=(MPNODE*)::malloc(m_size); node=node->next;
	}
	m_tail=node;
}

void* TMPool::Malloc()
{
	unsigned long len=sizeof(MPNODE);
	MPNODE *node=m_head;
	MPNODE *next=node->next;
	if(next==0)
	{
		node=(MPNODE*)::malloc(m_size); node->resv=0; return (char*)node+len;
	}	
	node->flag=1; m_head=next; return (char*)node+len; return 0;
}

void TMPool::Free(void *arg)
{
	MPNODE *node; unsigned long len=sizeof(MPNODE);
	
	node=(MPNODE*)((unsigned long)arg-len);
	if(node->resv==0)
	{
		::free((char*)arg-len); return;
	}
	if(node->flag==0) return;//这里很纠结
	node->flag=0;
	node->next=0; m_tail->next=node; m_tail=node;	
}

void TMPool::StaticFree(void *arg)
{
	MPNODE *node; TMPool *Mp; unsigned long len=sizeof(MPNODE);
	
	node=(MPNODE*)((unsigned long)arg-len);
	Mp=(TMPool*)node->resv;
	if(Mp==0)
	{
		::free((char*)arg-len); return;
	}
	if(node->flag==0) return;
	node->flag=0;
	node->next=0; Mp->m_tail->next=node; Mp->m_tail=node;
}

 

if(node->flag==0) return;//这里很纠结,这样防止重复释放肯定有问题,改成这样吧,还是觉得不太好

if(0==nterlockedExchange(&node->flag,0)) return;//这样可以防止多线程重复释放,问题是没有必要,因为重复释放本来就是应该杜绝的事情。不这样处理吧,又不甘心,因为重复释放隐患很大,有可能导致将来分配到地址相同的内存。

纠结……

望有能者可以依照此思路实现一个安全可用的内存池,分享一下,以满足伸手党的饥渴,言至此,非常感谢!

经过测试,发现debug下1秒崩溃的问题出在注释掉的那一行,已经修改。

 

还有,为什么许多代码都写在一行呢?这主要是CSDN这个编辑器使用起来有一定难度,一开始我想尽量让所有代码显示在一个页面内,于是就不断的缩减代码的纵向体积,才造成了这样的结果,虽然后来发现了其他办法,但代码已经被浓缩了,就这样吧。

 

很抱歉,愚笨是本人的老毛病了。

抱歉!评论已关闭.