3d Game Walkman

3d图形渲染,网络引擎 — tonykee's Blog
随笔 - 45, 文章 - 0, 评论 - 309, 引用 - 0
数据加载中……

对于线程资源竞争的改进

对于线程资源共用问题,实际上也没有一个最完美的解决方案,没有最适合的,只有根据情况来分析,找合适的方法,我最近在做角色之间的位置信息交换,已经实现了一部分了。感觉很爽
其中角色的位置在变,还要同时通知给所有其他的玩家,这其实应该是件头痛的问题
我前面的文章已经说明,我吧地形划分为一个个的tile,那么角色的信息只发送给身边9个tile里面其他的玩家,刚如果换了,tile,那么还要通知最后离开的三个tile里面的玩家,该角色已经不在可视范围之内了。这样的信息。那么就存tile里面同时要增加也要删除也要读取并且(发送)的处理
这些信息是具有高并发量的。如果处理的不好,角色是会很卡的。
我想了很久终于用一个巧妙的方法解决了这个难题,应该会比较高效的。
我定义了个这样的结构:

//某个线程的临时资源,在锁定一个资源的时候,可以根据需要,需要处理的数据拷贝到这个线程本地资源中去
//然后解锁再去处理这些数据,所占用的时间仅仅迭代和copy的时间,处理过程可以根据需要来决定是否应该同步(如果不同步,就不用占用临界锁了)
//可以从一定程度上,减少线程对资源的占有时间,减少线程碰撞机会,充分提高系统性能
//这种处理手法来源于java里面的ThreadLocal,里面的集合就是用来做为线程本地资源的。
//进程里面开辟的线程数量不会太多,本地资源应该有很多分类
typedef struct _LocalThreadResource
{
 DWORD ThreadId;  //当前线程的id

    //copy-process处理,这个特点都是从头往尾顺序加数据,不存在插入数据的情况,访问也是从头到尾,用vector最合适了
 //并且处理完了也不用清理(清理也要花时间),下次使用,复制的时候再从头到尾以iterator的方式copy
   
 vector<LPSESSION> mNotifingUsers;//本次线程需要通知给周围的角色id
 DWORD mNotifingUsersLen;  //保留上面集合的有效数据的集合的长度

    //根据需要添加更多的资源
} LocalThreadResource;

这个结构通过ThreadIdThreadId 关联到线程中去,当前的线程ID可以用GetThreadID来获取,


对于读取数据和处理的过程大致如下:




void TileInfo::Insert(LPSESSION playerid)
{
 mlock.lock();
 players.insert(playerid);
 mlock.unlock();
}

void TileInfo::Remove(LPSESSION playerid)
{
 mlock.lock();
 players.erase(playerid);
 mlock.unlock();
}

void TileInfo::SendMsgToPlayersInTile(BasePack *pack,int len, char *from)
{

 //得到当前的线程id
 DWORD currentThreadId = GetCurrentThreadId();
 //根据线程id得到当前线程的本地资源
 LocalThreadResource *localresource = gServer->LocalThreadResourceMap[currentThreadId];

 localresource->mNotifingUsers.resize(10);
 //加锁
 mlock.lock();
 //把需要处理的数据复制到线程本地资源,也许你对copy耿耿于怀,后来我思考了一下,其实不存在重新创建,而且数据量不大,简单的复制,速度是很快的,最大的好处,就是锁不用锁那么久,这点损失无妨。
 copy(players.begin(), players.end(), localresource->mNotifingUsers.begin());
 //记录需要处理的数据的长度
 localresource->mNotifingUsersLen = players.size();
 //解锁
 mlock.unlock();
    int i = 0;
    std::vector<LPSESSION>::iterator itor = localresource->mNotifingUsers.begin();
 //处理需要处理的线程本地数据
 for(; i < localresource->mNotifingUsersLen && itor!= localresource->mNotifingUsers.end(); itor++, i ++)
 {
   LPSESSION lpSession = (LPSESSION) *itor;
      gServer->SendInUdp(lpSession, (char *)pack, len, from);
 }
}

//把读取和处理过程完全分开,读数据和处理异步(减少锁占用的时间),读和写通过临界区来互斥。
我最终采纳了这个方案

posted on 2008-01-10 20:36 李侃 阅读(879) 评论(1)  编辑 收藏 引用 所属分类: 网络模块设计思路

评论

# re: 对于线程资源竞争的改进  回复  更多评论   

虽然完全看不懂,不过知道这是游戏程序也倍感亲切,继续加油,等待你出品的网游哦^_^
2008-01-22 01:10 | 絮絮

只有注册用户登录后才能发表评论。
网站导航: 博客园   IT新闻   BlogJava   知识库   博问   管理