- 浏览: 342446 次
- 性别:
- 来自: 福建福州
文章分类
最新评论
-
jw72jw:
最后这个是打表求值
LUA源码分析三:table分析(1) -
dyllove98:
"一些非常重要的问题,涉及面少。那这个时候,我更崇尚 ...
乱写:团队里的独裁和民主一点看法 -
jvmlover:
被踩10次了,什么思想感情啊。
LUA源码分析三:table分析(1) -
chenchenfly99:
chenchenfly99 写道
MMO游戏终极内测开服一周,问题记录 -
chenchenfly99:
...
MMO游戏终极内测开服一周,问题记录
前篇
在对象池的使用上,我采用了一前写的一个数组模拟链表的结构,并且做了修改。最大的发现就是,STL的偏特化特性导致空间不能配置的去NEW它,而VECTOR的标准结构里是将这一块隐藏起来的,用户只要不停的PUSH。不过解决的方法当然有,代码修改后丑陋了点:
ListOfArray.h的代码
#pragma once #include <assert.h> /** V0.2 2010/04/15 重新考虑了下add这个东西,赋值是一个operate = 的操作。如果你的类里有许多对象,那么按照C++对象的原则,你要为每个对象的 operate进行重写。这显然很烦琐,那么链表的使用上,自然的要以存储轻巧的对象来进行辅佐操作。那么这次在我做的一个内存定位中, 数组里的空间(ELEMENT ElementData[llist_size])在申明的时候已经有了个固定的ID,虽然也可以外部在弄一个,然后operate=,不过 几番思量下,直接暴露一个专门的地址出来,进行操作,方便得多。同时对整个类也进行了一些重构: 1.对一些名字进行了调整 2.因为配置的需要,加入new的方式 3.考虑到STL偏特化特点,加入一个参数,表示手动的给予参数,还是自动的使用llist_size v0.1 *原理很简单,将数组的元素看成是链表,或者说是数组空间起到了内存池的作用。然后用两个结点表示 *当前使用/空闲的链表. *链表的增加从头部增加 *连表以公用的NULL结尾 * *对效率的一些说明 *增:这个无需说,链表直接秒杀。 *删:类里提供的是一个ELEMENT结构,里面包含了用户的数据。如果你想保持常量的效率 *在一些数据接口提供是,也必须用ELEMENT,这样才能记住结点信息。否则你可以单开个你自己数据类型的接口 *但是在删除时,就必须遍历(删除方法见提供的实例) *ELEMENT类型的快速使用:typedef CListOfArray<type, 1000>::ELEMENT CListOfArray_t; *你维护好CListOfArray_t就行 **/ template<typename llist_t, int llist_size=100, bool bManual=false> class CListOfArray { //variable public: struct ELEMENT { llist_t element; ELEMENT* pPre; ELEMENT* pNext; }; private: int nMaxElementItem; ELEMENT *ElementData/*[llist_size]*/;//数组空间 ELEMENT ElementFreeHead; //空余的指针链头 ELEMENT ElementUseHead; //当前使用的指针链头 int nFreeSum; int nUseSum; //function public: CListOfArray() { nMaxElementItem = llist_size; if( false == bManual ) { InitList(); } } ~CListOfArray() { delete []ElementData; } void ManualAlloct(int nManualMaxItem) { nMaxElementItem = nManualMaxItem; InitList(); } bool Add(const llist_t e); ELEMENT* GetMallocElement() { return MallocElement(); } ELEMENT* Erase(ELEMENT *p) { return ReleaseElement(p); } void Empty(); ELEMENT* GetListUseHead() { return ElementUseHead.pNext; } ELEMENT* GetListFreeHead() { return ElementFreeHead.pNext; } int GetSumElementUse() { return nUseSum; } int GetSumElementFree() { return nFreeSum; } private: void InitList(); ELEMENT* MallocElement(); ELEMENT* ReleaseElement(ELEMENT *p); // //加到头部 void AddNodeToList(ELEMENT* const pNode, ELEMENT* const pDesListHead) { pNode->pNext = pDesListHead->pNext; pNode->pPre = pDesListHead; // //链表以NULL结尾,表示无节点。比如linux的list这里是做成循环的 if( NULL!=pDesListHead->pNext ) { pDesListHead->pNext->pPre = pNode; } pDesListHead->pNext = pNode; } }; /** *这里是大函数体定义 **/ template <typename llist_t, int llist_size, bool bManual> void CListOfArray<llist_t, llist_size, bManual>::InitList() { assert( nMaxElementItem>0 ); ElementData = new ELEMENT[nMaxElementItem]; nUseSum = 0; nFreeSum = llist_size; //开始串指针 for(int i=0; i<nMaxElementItem-1; ++i) { ElementData[i].pNext = &ElementData[i+1]; } ElementData[nMaxElementItem-1].pNext = NULL; ElementUseHead.pNext = NULL; ElementFreeHead.pNext = &ElementData[0]; } template <typename llist_t, int llist_size, bool bManual> typename CListOfArray<llist_t, llist_size, bManual>::ELEMENT* CListOfArray<llist_t, llist_size, bManual>::MallocElement() { //判断是否有空余元素 if( NULL==ElementFreeHead.pNext ) { return NULL; } --nFreeSum; ++nUseSum; //从Free链中脱出,头部 ELEMENT* p = ElementFreeHead.pNext; ElementFreeHead.pNext = ElementFreeHead.pNext->pNext; AddNodeToList(p, &ElementUseHead); return p; } template <typename llist_t, int llist_size, bool bManual> typename CListOfArray<llist_t, llist_size, bManual>::ELEMENT* CListOfArray<llist_t, llist_size, bManual>::ReleaseElement( ELEMENT *p) { --nUseSum; ++nFreeSum; ELEMENT *pResult = p->pNext; //从Use链中脱离 p->pPre->pNext = p->pNext; //判断是否是尾元素 if( NULL!=p->pNext ) { p->pNext->pPre = p->pPre; } AddNodeToList(p, &ElementFreeHead); return pResult; } template <typename llist_t, int llist_size, bool bManual> bool CListOfArray<llist_t, llist_size, bManual>::Add(const llist_t e) { //先从Free指针里取得一个空节点 ELEMENT *p = MallocElement(); if( NULL==p ) { return false; } else { p->element = e; return true; } } template <typename llist_t, int llist_size, bool bManual> void CListOfArray<llist_t, llist_size, bManual>::Empty() { // //最快捷方法是将ElementUseHead直接连到ElementFreeHead末尾。考虑到平常使用不多,Empty仅是测试使用 //暂时不重写,保持用Erase ELEMENT* p = GetListHead(); while( NULL!=p ) { p = Erase(p); continue; p=p->pNext; } }
Main文件的调用代码:
// HelloTest.cpp : Defines the entry point for the console application. // #include "stdafx.h" #include "ListOfArray.h" const int MAX_TESTOBJECT_ITEM = 100; const int MAX_MANUAL_TESTOBJECT_ITEM = 100; class CNet { public: bool bEnable; int nIdenti; private: public: CNet() { bEnable = false; } private: }; class CLogic { public: bool bEnable; int nIdenti; private: public: CLogic() { bEnable = false; } private: }; typedef CListOfArray<CNet,MAX_TESTOBJECT_ITEM, true> CListOfArrayT; typedef CListOfArray<CNet,MAX_TESTOBJECT_ITEM, true>::ELEMENT CListOfArray_t; // // void PrintListInfo(CListOfArrayT *pNetList) { cout<<"PrintListInfo--------:"<<endl; cout<<"SumUse:"<<pNetList->GetSumElementUse()<<endl; cout<<"SumFree:"<<pNetList->GetSumElementFree()<<endl; } bool Connect(CListOfArrayT *pNetList, CLogic *pLogicArray) { CListOfArray_t *pGetNetItem = pNetList->GetMallocElement(); if( NULL==pGetNetItem ) { return false; } pGetNetItem->element.bEnable = true; pLogicArray[ pGetNetItem->element.nIdenti ].bEnable = true; return true; } void DisConnect(CListOfArrayT *pNetList, CLogic *pLogicArray) { int nSumUse = pNetList->GetSumElementUse(); CListOfArray_t *pGetNetItem = pNetList->GetListUseHead(); if( 0==nSumUse ) { // //没有节点了 return; } int nErase = rand()%nSumUse; for(int i=0; i<nErase; ++i) { pGetNetItem = pGetNetItem->pNext; } pGetNetItem->element.bEnable = false; pLogicArray[ pGetNetItem->element.nIdenti ].bEnable = false; pNetList->Erase(pGetNetItem); } void TestStep1( CListOfArrayT *pNetList, CLogic *pLogicArray, int nCount) { for(int i=0; i<nCount; ++i) { if( false==Connect(pNetList, pLogicArray)) { cout<<"step 1 Connect Full"<<endl; } } } void TestStep2( CListOfArrayT *pNetList, CLogic *pLogicArray, int nCount) { for(int i=0; i<nCount; ++i) { int j=rand()%2; if( 0==j ) { //增加 if( false==Connect(pNetList, pLogicArray)) { cout<<"step 2 Connect Full"<<endl; } } else { //随机删除 DisConnect(pNetList, pLogicArray); } } } void VerifyEnable(CListOfArrayT *pNetList, CLogic *pLogicArray) { cout<<"VerifyEnable--------:"<<endl; // //进行个数比对 int nSumNetList = pNetList->GetSumElementUse(); int nSumLogicArray = 0; for(int i=0; i<MAX_TESTOBJECT_ITEM; ++i) { if( true==pLogicArray[i].bEnable ) { nSumLogicArray++; } } cout<<"nSumNetList:"<<nSumNetList<<endl; cout<<"nSumLogicArray:"<<nSumLogicArray<<endl; // //进行Identi比对 int nLogicArrayIndex; CListOfArray_t *pGetNetUseItem = pNetList->GetListUseHead(); CListOfArray_t *pGetNetFreeItem = pNetList->GetListFreeHead(); for(; NULL!=pGetNetUseItem; pGetNetUseItem=pGetNetUseItem->pNext) { nLogicArrayIndex = pGetNetUseItem->element.nIdenti; if( pGetNetUseItem->element.bEnable!=pLogicArray[nLogicArrayIndex].bEnable ) { cout<<nLogicArrayIndex<<" error!!!!!"<<endl; } } for(; NULL!=pGetNetFreeItem; pGetNetFreeItem=pGetNetFreeItem->pNext) { nLogicArrayIndex = pGetNetFreeItem->element.nIdenti; if( pGetNetFreeItem->element.bEnable!=pLogicArray[nLogicArrayIndex].bEnable ) { cout<<nLogicArrayIndex<<" error!!!!!"<<endl; } } } int _tmain(int argc, _TCHAR* argv[]) { srand( (unsigned)time( NULL ) ); int i; CListOfArrayT NetList; CLogic LogicArray[MAX_TESTOBJECT_ITEM]; NetList.ManualAlloct(MAX_TESTOBJECT_ITEM); // //ID初试化 CListOfArray_t *pListItem = NetList.GetListFreeHead(); for(i=0; i<MAX_TESTOBJECT_ITEM; ++i) { pListItem->element.nIdenti = i; LogicArray[i].nIdenti = i; pListItem = pListItem->pNext; } TestStep1(&NetList, LogicArray, 982); TestStep2(&NetList, LogicArray, 3000); TestStep1(&NetList, LogicArray, 910); TestStep2(&NetList, LogicArray, 600); TestStep2(&NetList, LogicArray, 760); // //结果ID比对 VerifyEnable(&NetList, LogicArray); // //查看分布情况 PrintListInfo(&NetList); PrintArrayInfo(LogicArray); return 0; }
我在调用中,模拟了一个连接进来后,从网络对象中取得对象,然后对比的也从上层的逻辑中取得。原理很简单,一个序列化的ID。 Main里的代码主要是比对2个对象集合间的值是否一一对应。目前暂时没发现什么BUG,欢迎提交
发表评论
-
【创业】找味道相同程序员
2013-10-29 12:06 30我觉得写招聘,就是在找味道一样的人。但是团队正起步中,没有 ... -
0到新浪微博综搜榜第一
2012-12-27 09:38 19900到新浪微博综搜榜第一 原谅我标题了一点,这两天 ... -
看事儿网:下一代社交内容分析和demo展示
2012-10-31 11:26 1715兄弟我最近用业余时间学了点WEB的东西,做了个自己设想中 ... -
总结第一个项目"种粉网"的失败
2012-08-07 10:45 1295第一个项目“种粉网 ... -
当年朦胧的程序员我,在游戏上对聊天玩法新的包装想法。。
2011-10-13 22:48 1508下班回家的路上,在 ... -
Google Protocol Buffer“序列化.写入”代码流程一点分析
2011-06-09 23:34 16695(为啥在可视化编辑里的字都好好的,出来后就忽大忽小的,尤其在代 ... -
2010 ECUG大会,第二天记录。
2010-10-17 21:35 1133第二天 早上爬了几次才起来。一路小跑,买完包子后在 ... -
2010 ECUG大会,第一天记录。
2010-10-16 22:29 1218ECUG:http://ecug.org/2010:home ... -
缓存的力量,windows下的slub分配器
2010-07-13 14:58 2292上张图先: 该CPU L2=3MB 首先谈谈对象分 ... -
IOCP的分层一
2010-04-13 16:09 1365写网络代码时,总希望把逻辑和网络层分开。而在IOC ... -
~也来共享共享我的程序学习方法~
2010-03-03 22:23 856一家之言,如果你觉得天天看书无效、纠结语法的时候可以 ... -
(00XX系列)搞搞有限状态机
2009-11-12 17:02 1420需要修改游戏中的一些AI,自己做了个小模型。一 ... -
万恶的继承
2009-10-28 23:36 825(1) 关于人物继承: cla ... -
一篇以前写过的文章:C++之一个编程入门者的感悟(能引起你的共鸣,是我最值得的事)
2009-03-11 13:29 878今日再看到这篇文章实 ... -
我怎么就想个留个电话,该留个邮箱啊。
2009-01-06 11:18 1055跟客户交流完问题后,一些问题还没得到解决。客户拿了张纸叫我把一 ... -
说出“对不起”的感觉真好
2008-12-30 21:38 1497早上,在聚精会神看书中。一同事突然问我:“XX,关于。。。。” ... -
观察和留意细节
2008-12-06 12:33 925周五下午回公司开会。 在会议室门外,已经坐着几个同组的同事。 ... -
就算说话很随便,关系再好的人,也要注意用词用语
2008-12-03 22:54 1614如下: 中午,组长因为少了个椅子,来我旁边搬走张椅子(我是用 ... -
今日反思:对简单程序的不重视
2008-11-24 23:04 927一个很简单的UDP/TCP/服务器连接。 不怎么重视,很随意的 ... -
内网呆了一周,一些奇怪的问题记录下。。
2008-09-05 22:17 1258内网呆了一周,一些奇怪的问题记录下。。 这个是很久以前的 协 ...
相关推荐
结合这两个概念,"IOCP 内存池线程池"意味着在一个基于IOCP的系统中,线程池中的工作线程使用了内存池来管理用于收发I/O操作的内存缓冲区。这样的设计能显著提升网络服务、数据库服务器等需要大量并发I/O操作的应用...
本篇文章将通过一个最简单的IOCP示例,深入探讨其工作原理和使用方法。 首先,我们来看看IOCP的基本概念。IOCP是Windows系统提供的一种I/O模型,它允许应用程序通过单一的线程池来处理所有的I/O完成事件,极大地...
面向对象的IOCP(I/O完成端口)模板类在C#编程中是一个高效的设计模式,主要用于处理大量的并发I/O操作。IOCP是Windows操作系统提供的一种异步I/O模型,它能够有效地处理大量并发的网络连接,从而提高服务器的性能和...
1. **创建I/O完成端口**:使用`CreateIoCompletionPort`函数创建,可以为一个文件句柄或网络套接字关联到IOCP,以便后续的I/O操作完成后,结果会被发送到这个端口。 2. **提交I/O请求**:通过调用`TransmitFile`、`...
综上所述,IOCPServer.rar 包含的项目是一个精心设计的服务器实现,它利用了 Windows 平台上的 I/O 完成端口技术,配合线程池和内存池策略,旨在提供一个高度优化、可扩展的服务器解决方案。开发者可以通过分析和...
1. **创建IOCP**:首先,服务器需要调用`CreateIoCompletionPort`函数创建一个IOCP对象。这个对象是所有后续I/O操作的中心。 2. **绑定Socket到IOCP**:服务器需要为每个监听套接字和连接套接字绑定到IOCP上,这样...
总的来说,这个压缩包中的内容可能是实现了一个基于IOCP和多线程池的高效并发服务,可以用于处理大量并发的网络连接,如服务器端的应用程序。通过深入研究这些源代码,我们可以学习到如何在实际应用中有效地利用这两...
IOCP是Windows系统内核提供的一个同步I/O管理对象,它允许多个线程等待同一组I/O操作的完成。当I/O操作完成后,系统会将完成信息放入IOCP,等待的线程可以从IOCP中取出这些信息并进行后续处理。这种设计使得服务器...
1. **创建Completion Port**:程序首先创建一个Completion Port对象,所有的I/O操作都会关联到这个Port上。 2. **创建Socket并绑定到IOCP**:创建Socket后,通过`CreateIoCompletionPort`函数将Socket与IOCP关联...
当一个I/O请求发起后,系统会将该请求挂起,并在I/O操作完成后唤醒一个等待的线程,而不是为每个I/O请求创建新的线程。这种设计减少了线程上下文切换的开销,提升了系统的整体性能。 ### 2. IOCP.NET库的核心功能 ...
1. 初始化IOCP,创建一个IOCP对象。 2. 创建或获取需要进行异步I/O操作的句柄(如套接字),并将其与IOCP关联。 3. 使用异步I/O函数发起读写操作,设置好`OVERLAPPED`结构。 4. 创建并启动线程池,线程将不断地从...
IOCP的基本工作原理是这样的:当一个I/O操作开始时,不会立即阻塞当前线程,而是将其请求放入完成端口,然后由系统调度其他线程来处理完成后的结果。这种方式使得线程可以立即返回执行其他任务,而无需等待I/O操作...
标题中的“一个对IOCP进行封装的DLL”指的是一个动态链接库(DLL)文件,它将Windows操作系统中的I/O完成端口(I/O Completion Port,简称IOCP)进行了抽象和封装,使得开发者无需深入理解底层的IOCP机制,也能利用...
1. **创建IOCP**:首先,需要调用`CreateIoCompletionPort`函数创建一个IOCP对象。这个对象用于存储和管理所有与之关联的I/O操作完成信息。 2. **关联设备或套接字**:接着,将需要进行I/O操作的设备(如硬盘)或套...
IO Completion Port...通过CreateIoCompletionPort函数来创建一个IOCP对象,这个函数的原型为HANDLE CreateIoCompletionPort(HANDLE FileHandle, HANDLE ExistingCompletionPort, ULONG_PTR CompletionKey, DWORD ...
2. 完成端口:IOCP是一个系统对象,用于接收已完成的I/O操作通知,从而调度相应的处理线程。 3. 工作线程池:IOCP通过工作线程池来处理完成的I/O请求,线程池中的线程数量可以根据系统负载动态调整。 二、IOCP...
总结来说,"windows iocp网络通讯库封装"是一个利用Windows IOCP技术构建的C++网络通信库,它通过`ITcpClient`和`ITcpServer`接口为开发者提供了简单易用的客户端和服务器端功能,同时借助`libsocket.dll`和`...
1. **完成端口对象**:IOCP是系统创建的一个对象,用于接收和管理完成的I/O操作。应用程序通过CreateIoCompletionPort函数创建并关联到特定的设备或套接字。 2. **提交I/O请求**:使用诸如TransmitFile、WSASend、...
在本项目中,我们有一个简单的IOCP服务器和客户端类实现,这将帮助我们理解如何利用IOCP来构建高性能的网络服务。 1. **IOCP基本概念** - I/O模型:包括同步I/O、异步I/O和完成端口I/O等。IOCP是异步I/O的一种高效...