/* Handle类通常是只读的无符号整数。虽然可以安全地将其设为空来重置句柄,但句柄一旦创建就不应该再修改。 注意,Handle是参数化的类,需要一个TAG类型来完整定义。 模板参数TAG除了区分句柄类型外不起任何作用,TAG类型的对象在系统任何地方都不会被用到。 这么做的原因是为了保证类型安全。使用参数化的Handle类型可以确保,如果向期望获取某种类型句柄的 函数传递另外一种类型的句柄,则不会被编译通过。 因此为了保障类型安全,我们创建一个新的句柄类型, 作为一个唯一符号并被用作Handle类型的参数。TAG类型可以是任何形式的类型. */ #ifndef _DEBUG #include //#include #endif //#include //#include //实现对象的重用,而且管理实体 //参见: http://hi.baidu.com/zyb_debug/blog/item/eaf6ea8ce55f291bb21bba4c.html #pragma once enum { // sizes to use for bit fields 使用位域(bit fields)的大小 MAX_BITS_INDEX = 21, MAX_BITS_MAGIC = 11, // sizes to compare against for asserting dereferences MAX_INDEX = ( 1 << MAX_BITS_INDEX) - 1, MAX_MAGIC = ( 1 << MAX_BITS_MAGIC) - 1, //INVALID_INDEX =( 1 << MAX_BITS_INDEX), //非法的INDEX }; //TAG在这里并没有什么用处, template class Handle { union { struct { unsigned m_Index : MAX_BITS_INDEX; // index into resource array 资源数组的索引 unsigned m_Magic : MAX_BITS_MAGIC; // magic number to check 需要检查的魔术数 }; unsigned int m_Handle; }; public: // Lifetime.生命期 Handle( void ) : m_Handle( 0 ) { } Handle( unsigned nHandle ) {m_Handle= nHandle ;} // void Init( unsigned int index ) { DbgAssert( IsNull() ); // don't allow reassignment 不允许重新赋值 DbgAssert( index <=MAX_INDEX ); // verify range 有限范围验证 //魔数初始化修改为一个随机数,避免出现一些特殊情况,增加服务器重启后可靠性 static unsigned int s_AutoMagic = rand(); IncMagicNumImpl(s_AutoMagic); m_Index = index; m_Magic = s_AutoMagic; } inline void updateMagic() { unsigned int magic = m_Magic; IncMagicNumImpl(magic); m_Magic = magic; } // Query.查询 inline unsigned int GetIndex ( void ) const { return ( m_Index ); } inline unsigned int GetMagic ( void ) const { return ( m_Magic ); } inline unsigned int GetHandle( void ) const { return ( m_Handle ); } bool IsNull ( void ) const { return ( !m_Handle ); } inline unsigned GetMaxIndex(){return MAX_INDEX;} operator unsigned int ( void ) const { return ( m_Handle ); } protected: inline void IncMagicNumImpl(unsigned int &magic) { if ( ++magic > MAX_MAGIC ) magic = 1; // 0 is used for "null handle" } }; template class HandleMgr { public: typedef DATA DataType; typedef HANDLE HandleType; //typedef HandleMgrStat Inherited; HandleMgr(LPCTSTR lpszDesc); ~HandleMgr( ) { Empty(); } //申请一个数据指针 DATA* Acquire( HANDLE& handle ); //不使用指针,放到缓存池里去 void Release( HANDLE handle ); // 重新请求一个新句柄 bool ReNew( HANDLE &handle); // 通过handle返回数据的指针 DATA* GetDataPtr( HANDLE handle ); const DATA* GetDataPtr( HANDLE handle ) const; // other query 其他查询 inline unsigned int GetUsedHandleCount( void ) const { return ( m_nUsedCount ); } inline UINT GetTotalHandleCount(void) { return (UINT)m_MagicNumbers.count() * ONE_CHUNK_COUNT; } inline int GetUserDataSize(void) { return m_nUsedCount * (sizeof(DATA) + ONE_CHUNK_COUNT); } inline bool HasUsedHandles( void ) const { return ( (GetTotalHandleCount() -GetUsedHandleCount()) >0 ); } inline VOID GetChunkIdPos(UINT index, UINT &nChunkId, UINT & nPos) { nPos = index % ONE_CHUNK_COUNT; //取在chunk里的位置; //取在chunk里的位置 nChunkId = index / ONE_CHUNK_COUNT; //在第几个chunk } //通过数据指针释放 void ReleaseDataPtr( DATA * pData ); //获取第1个有效的数据指针,结果的句柄要放在 hHandle,数据指针放在DATA* DATA * First(HANDLE & hHandle); DATA * Next(HANDLE & hHandle); //hHandle 句柄 下一个有效数据的指针,DATA 为该数据指针 //清空内存 void Empty(); // 输出统计信息到文件 void dumpToFile() { } private: // private types // typedef wylib::container::CBaseList< wylib::container::CBaseList > UserVec; //数据 typedef wylib::container::CBaseList< wylib::container::CBaseList > MagicVec; //handle typedef wylib::container::CBaseList< unsigned int> ChunkFreeCountVec; //每个块还有多少个空闲的句柄 UINT m_nFirstFreeIndex ; //第1个能用的index,这个用于指向释放了的第1个可用index UINT m_nLastChunkFirstFreeIndex; //新申请的空闲列表的一个第1个可用的index UINT m_nUsedCount; // // private data UserVec m_UserData; // 数据 MagicVec m_MagicNumbers; // 存的是每个数据当前使用的句柄 ChunkFreeCountVec m_FreeCounts; //每个块有多少个空闲的元素,这个保证每次查找可用的指针最多查找1024个对象 const static UINT INVALID_INDEX = ~0 ; //非法的指针 //const static int ONE_CHUNK_COUNT =1024 ; //每次申请1024个空间,这个要是2的n次幂 //const static int CHUNK_SHIFT_BIT_COUNT =10; //移位ONE_CHUNK_COUNT 需要移位运送多少位 //const static int CHUNK_MASK=0x3ff ; //取在1024块里的位置 }; template inline bool operator != ( Handle l, Handle r ) { return ( l.GetHandle() != r.GetHandle() ); } template inline bool operator == ( Handle l, Handle r ) { return ( l.GetHandle() == r.GetHandle() ); } template HandleMgr :: HandleMgr(LPCTSTR lpszDesc = NULL) { m_nFirstFreeIndex = INVALID_INDEX; m_nLastChunkFirstFreeIndex = INVALID_INDEX; m_nUsedCount =0; } template void HandleMgr ::Empty() { for(INT_PTR i=0; i~DATA(); } TRACE(_T("Node not releaseed on HanderMgr destroy,DataSize =%d, hander=%d,index=%d\n"),sizeof(DATA),hd.GetHandle(),hd.GetIndex()); //OutputMsg(rmError,_T("Node not releaseed on HanderMgr destroy,DataSize =%d, hander=%d,index=%d"),sizeof(DATA),hd.GetHandle(),hd.GetIndex()); } } m_UserData[i].empty(); } for(INT_PTR i=0; i DATA* HandleMgr :: Acquire( HANDLE& handle ) { // if free list is empty, add a new one otherwise use first one found 如果空闲列表为空,则新增一个,否则使用第一个可用表项 UINT index =INVALID_INDEX; UINT nChunkId =0,nPos=0; //如果前面有空闲的位置,优先使用空闲的对象 if (m_nFirstFreeIndex != INVALID_INDEX) { index = m_nFirstFreeIndex; GetChunkIdPos(m_nFirstFreeIndex,nChunkId,nPos); // 获取当前空闲句柄的位置(在第几块的第几个槽) m_nFirstFreeIndex = INVALID_INDEX; // 设置当前空闲有效句柄为INVALID_INDEX //查找一个空闲的 for(INT i =nChunkId ; i < (INT)m_MagicNumbers.count(); i++) // m_MagicNumbers.count() 是数据块的数目 { //只有在这个块有空闲的才去查找,避免了无效的查询,最多1024个 bool bFindNextFreeItem = false; INT nFreeCount = m_FreeCounts[i]; if( nFreeCount > 0 ) { INT j =0; if( nChunkId == i ) //如果是本块,那么从后一个查起 { j = nPos +1; if(nFreeCount ==1) //本块只有1块,那肯定用过了阿 { continue; } } CBaseList & pHandChunk = m_MagicNumbers[i]; // 第i块的句柄数据 for (; j < ONE_CHUNK_COUNT; j++) { //HANDLE hTemp = ; if( pHandChunk[j].GetMagic() ==0) { m_nFirstFreeIndex = (i * ONE_CHUNK_COUNT) + j;// 下一个空闲句柄位置 bFindNextFreeItem = true; break; } } } if (bFindNextFreeItem) break; } //如果其已经到了空闲列表的最后一个了,那么说明前面已经没有可用使用的了 if (m_nFirstFreeIndex == m_nLastChunkFirstFreeIndex) { m_nFirstFreeIndex = INVALID_INDEX; } } else { if(m_nLastChunkFirstFreeIndex == INVALID_INDEX ) //if no chunk { //已经无法申请了 UINT nTotalCount = GetTotalHandleCount(); Assert(nTotalCount == GetUsedHandleCount()); if ( (unsigned int) nTotalCount >= handle.GetMaxIndex()) return NULL; //已经无法申请了,超过了最大数量 CBaseList dataChunk; CBaseList handleChunk; m_UserData.addArray(&dataChunk,1); //添加到列表 m_MagicNumbers.addArray(&handleChunk,1); INT_PTR nBackIndex = m_UserData.count(); // m_UserData.count() 是当前数据块的块数目 if (nBackIndex <1) return NULL; nBackIndex --; // 最后一个块的索引 m_UserData[nBackIndex].reserve(ONE_CHUNK_COUNT); // 保证每个块都是同样长度 m_UserData[nBackIndex].trunc(ONE_CHUNK_COUNT); m_MagicNumbers[nBackIndex].reserve(ONE_CHUNK_COUNT); m_MagicNumbers[nBackIndex].trunc(ONE_CHUNK_COUNT); HANDLE *pHandle = m_MagicNumbers[nBackIndex]; // 最后一个句柄块 memset(pHandle,0,sizeof(HANDLE) *ONE_CHUNK_COUNT ); // 初始化最后一个句柄块 //使用placement new 调用构造函数 m_nLastChunkFirstFreeIndex = nTotalCount; //当前的最大数量,指向下一个 m_FreeCounts.add(ONE_CHUNK_COUNT); //这个块还有多少个没有使用 //m_nAllocedChunkCount++; } if(m_nLastChunkFirstFreeIndex != INVALID_INDEX) { index = m_nLastChunkFirstFreeIndex; m_nLastChunkFirstFreeIndex ++; //指向下一个 if(m_nLastChunkFirstFreeIndex >= (unsigned) GetTotalHandleCount()) //如果这个块使用完了,就需要重新申请空间了 { m_nLastChunkFirstFreeIndex = INVALID_INDEX; } } } //实在是找不到可以使用的了 if ( index == INVALID_INDEX) return NULL; handle.Init( index ); GetChunkIdPos(index,nChunkId,nPos); unsigned int nFreeCount = m_FreeCounts[nChunkId]; if (nChunkId < (UINT)m_MagicNumbers.count() && nFreeCount >0 ) { m_MagicNumbers[nChunkId][nPos] =handle; } else { return NULL; } m_FreeCounts[nChunkId]--; //这个列表空闲的数量 DATA *pData = &(m_UserData[nChunkId][nPos]); new(pData)DATA();//placement new m_nUsedCount++; //m_nUsedHdlCount++; //if (m_nUsedHdlCount > m_nMaxUsedHandleCount) // m_nMaxUsedHandleCount = m_nUsedHdlCount; return pData; } template void HandleMgr :: ReleaseDataPtr( DATA * pData ) { UINT_PTR count =m_UserData.count(); SIZE_T nChunkSize = ONE_CHUNK_COUNT * sizeof(DATA); //每一块Chunk的大小,每次申请1024个 UINT_PTR nEndIndex = ONE_CHUNK_COUNT -1; //1023 for (UINT_PTR i= 0;i< count; i++) { DATA * pStart = &m_UserData[i][0]; DATA * pEnd = &m_UserData[i][nEndIndex]; INT_PTR nDataIndex = pData -pStart; //第多少个数据 if(nDataIndex >= 0 && pData <= pEnd) //找到了这个内存块 { INT_PTR nByteDis = (char *)pData - (char *)pStart; if( nByteDis % sizeof(DATA) != 0) //内存长度错误 { return; } Release( m_MagicNumbers[i][nDataIndex] ); return; } } } template void HandleMgr :: Release( HANDLE handle ) { // which one? 哪一个 if ( handle.IsNull() )return; unsigned int index = handle.GetIndex(); UINT nChunkId =0,nPos=0; GetChunkIdPos(index,nChunkId,nPos); if( nChunkId >= (UINT)m_MagicNumbers.count() ) return ; //有问题,已经超过了 if (m_MagicNumbers[nChunkId][nPos].GetMagic() != handle.GetMagic()) return; //重复释放 // ok remove it - tag as unused and add to free list 可以删除了--表及其没有使用并加到空闲列表 if (index < m_nFirstFreeIndex ) { m_nFirstFreeIndex = index; } HANDLE hTemp; m_MagicNumbers[nChunkId][nPos] =hTemp; //调用析构函数 DATA *pdata =&( m_UserData[nChunkId][nPos]); if(pdata) { pdata->~DATA(); } m_FreeCounts[nChunkId] ++; //这个块的空闲的个数 -1 m_nUsedCount--; //m_nUsedHdlCount--; } template bool HandleMgr :: ReNew( HANDLE &handle) { if (handle.IsNull()) return false; // check handle validity unsigned int index = handle.GetIndex(); UINT nChunkId =0,nPos=0; GetChunkIdPos(index,nChunkId,nPos); if (nChunkId > (UINT)m_MagicNumbers.count() || m_MagicNumbers[nChunkId][nPos].GetMagic() != handle.GetMagic()) return false; handle.updateMagic(); m_MagicNumbers[nChunkId][nPos] = handle; return true; } template inline DATA* HandleMgr :: GetDataPtr( HANDLE handle ) { if ( handle.IsNull() ) return ( 0 ); unsigned int index = handle.GetIndex(); UINT nChunkId =0,nPos=0; GetChunkIdPos(index,nChunkId,nPos); // check handle validity - $ this check can be removed for speed 检查句柄有效性-为提供性能可以去掉这个检查 // if you can assume all handle references are always valid. 如果你假设索引句柄解引用都总是有效 if( nChunkId >=(UINT)m_MagicNumbers.count()) return NULL; //有问题, if (m_MagicNumbers[nChunkId][nPos].GetMagic() != handle.GetMagic()) return NULL; //重复释放 return (& m_UserData[nChunkId][nPos] ); } template inline const DATA* HandleMgr :: GetDataPtr( HANDLE handle ) const { // this lazy cast is ok - non-const version does not modify anything typedef HandleMgr ThisType; return ( const_cast ( this )->GetDataPtr( handle ) ); } //获取第1个有效的数据指针,结果的句柄要放在 hHandle,数据指针放在DATA* template DATA* HandleMgr ::First(HANDLE & hHandle) { INT_PTR count= m_FreeCounts.count(); for(int i=0; i< count; i++) { if(ONE_CHUNK_COUNT- m_FreeCounts[i] >0 ) //如果一个块里有数据,那么就在这个块里找 { for(INT_PTR j=0; j< ONE_CHUNK_COUNT; j++) { if(m_MagicNumbers[i][j] != 0) { hHandle = m_MagicNumbers[i][j]; return &m_UserData[i][j]; } } } } return NULL; } //hHandle 句柄 下一个有效数据的指针,DATA 为该数据指针 template DATA* HandleMgr :: Next(HANDLE & hHandle) { if(hHandle ==0) return NULL; //压根就没有输入 UINT index = hHandle.GetIndex(); UINT nChunkId =0,nPos=0; GetChunkIdPos(index,nChunkId,nPos); for(INT_PTR i =nChunkId ; i < m_MagicNumbers.count(); i++) { //只有在这个块有空闲的才去查找,避免了无效的查询,最多1024个 INT_PTR nFreeCount = m_FreeCounts[i]; if( ONE_CHUNK_COUNT- nFreeCount >0 ) { INT_PTR j =0; if( nChunkId == i ) //如果是本块,那么从后一个查起 { j = nPos +1; if(nFreeCount ==1) //本块只有1块,那肯定用过了阿 { continue; } } CBaseList & pHandChunk = m_MagicNumbers[i]; for (; j < ONE_CHUNK_COUNT; j++) { //HANDLE hTemp = ; if( pHandChunk[j].GetMagic() !=0) { hHandle = pHandChunk[j]; return &m_UserData[i][j]; } } } } return NULL; }