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

来源:互联网 发布:windows 运行指令 编辑:程序博客网 时间:2024/05/09 04:11

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#endifstruct 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这个编辑器使用起来有一定难度,一开始我想尽量让所有代码显示在一个页面内,于是就不断的缩减代码的纵向体积,才造成了这样的结果,虽然后来发现了其他办法,但代码已经被浓缩了,就这样吧。

 

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

原创粉丝点击