关于mangos多线程处理方式

由于目前的MANGOS只是针对个人单机用户制作的,并非真正的服务器版。使用的是单 线程的处理方式。
关于mangos多 线程处理方式

听说配置这个文件是管理 线程的,不过不知道有没有用!
# 在多 线程系统 使用线程MASK(只在Windows系统下使用)
# 默认: 0 (操作系统来选择)
# 举例: 数字
UseProcessors = 0

目前的mangos上了几十人后,只要有组队的组团的就会卡,奇怪CPU占用也不高。请教了大大之后明白原来是mangos自身的瓶颈问题。

CK说:
由于目前的MANGOS只是针对个人单机用户制作的,并非真正的服务器版。使用的是单 线程的处理方式。这个由代码就可以看出,整个World(包括人物,怪等)都是靠World.cpp里的update函数发起掉用的。而他是使用单 线程的方式,从头遍历所有的玩家,一个一个按照次序的来进行获取封包,并处理然后发送。这也就是为什么,当你打开MANGOS这个服务端,竟然CPU占用很少的原因。
在网上,我也看到过有人打算用多开区(EXE)来达到玩家分流,也只是治表不治本的方法。按照MANGOS的框架总体上来说人数达到100其实是一个上限值再上去的话,可能情况就是PING值虽然不高,但还是觉得卡。因为玩家封包没有及时处理,而停留在“等待处理”中。卡怪,卡魔法这样的情况很容易产生。特别当有一个PING值非常高的玩家,在SESSION排队列表里比你靠前时,这种情况最容易发生。

CK给出的代码:
在World.cpp文件里,做一个 线程函数来代替
update函数里的

CODE:

for (SessionMap::iterator itr = m_sessions.begin(), next; itr != m_sessions.end(); itr = next)
  {
  next = itr;
  next++;

  if(!itr->second)
    continue;

  if(!itr->second->Update(diff))
  {
    delete itr->second;
    m_sessions.erase(itr);
  }
  }
[url=javascript:][Copy to clipboard][/url]

以上代码就是我刚才说的,从头遍历所有玩家并依次调用,所有玩家session的update函数。以下是修正建立自己的 线程
CODE:

DWORD World::_UpdateThread(LPVOID lp)
{
ThreadParm *parm = (ThreadParm *)lp;
World *pworld = (World *)parm->world;
HANDLE m_hSingle = NULL;
while (true)
{
  SessionMap sessions = pworld->GetSessions();
  SessionMap::iterator itr = NULL;
  SessionMap::iterator next = NULL;

  for (itr = sessions.begin(), next; itr != sessions.end(); itr = next)
  {
    next = itr;
    next++;

    if(itr == NULL || !itr->second || itr->second->GetWorking())
      continue;

    m_hSingle = OpenEvent(EVENT_ALL_ACCESS,true,"worldsession"); //这里必须对所操作资源进行同步处理,否则将会出现 线程之间资源访问的冲突。一个 线程处理一个玩家,其他 线程直接跳转到后面的列队
    if (m_hSingle == NULL)
    {
      m_hSingle = CreateEvent(NULL, FALSE, TRUE, "worldsession");
    }
    if (WaitForSingleObject(m_hSingle, 10000) == WAIT_TIMEOUT)//我把超时设置为10秒,以防死锁
    {
      SetEvent(m_hSingle);
      m_hSingle = CreateEvent(NULL, FALSE, TRUE, "worldsession");
    }
    itr->second->SetWorking(true);
    SetEvent(m_hSingle); //记得别忘了把锁打开,否则这个玩家之后所有的封包操作将被忽略。
    if (!itr->second->Update(time(NULL)))
    {
      pworld->RemoveErrorSession(itr->second->GetAccountId());
    }
    else
    {
      itr->second->SetWorking(false);
    }
  }
  Sleep(100); //线程间隔时间我设置为0.1秒
}
return 0;
}
[url=javascript:][Copy to clipboard][/url]

接下来就是如何去开启 线程进行处理了,在world.cpp里有个SetInitialWorldSettings函数,这个是初始化World里面所有数据的总入口。我们可以把 线程启动放那里。
先在mangosd.conf文件里设置一串
CODE:
WorldSessionThread = 3
[url=javascript:][Copy to clipboard][/url]
设置3个启动 线程
接下去就是在SetInitialWorldSettings里修改了
CODE:

....
sLog.outString( "Loading Loot Tables..." );
LoadLootTables();
//在这里添加我们的 线程函数
for (int i = 0; i diff = i;
  t->world = this;
  ::CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)_UpdateThread,(LPVOID)t,0,&tid);
}
[url=javascript:][Copy to clipboard][/url]
GetIntDefault函数第一个我就不解释了,第二个值是表示默认值,比如你配置文件里没设置WorldSessionThread = 3这条语句的话,默认就是2个 线程

这样一来,我们的MANGOS服务端在处理能力上,将得到很大的提升


龙苑的林碧给出的提示:
thread.cpp

#include <stdio.h>
#ifdef _WIN32
#include "socket_include.h"
#else
#include <unistd.h>
#endif

#include "Thread.h"

#ifndef __GNUC__

// UQ1: warning C4311: 'type cast' : pointer truncation
#pragma warning(disable:4311)

#endif

Thread::Thread(bool release)
:m_thread(0)
,m_running(true)
,m_release(false)
{
#ifdef _WIN32
m_thread = ::CreateThread(NULL, 0, StartThread, this, 0, &m_dwThreadId);
#else
pthread_attr_t attr;

pthread_attr_init(&attr);
pthread_attr_setdetachstate(&attr,PTHREAD_CREATE_DETACHED);
if (pthread_create(&m_thread,&attr,StartThread,this) == -1)
{
  perror("Thread: create failed");
  SetRunning(false);
}
//   pthread_attr_destroy(&attr);
#endif
m_release = release;
}


Thread::~Thread()
{
//   while (m_running || m_thread)
if (m_running)
{
  SetRunning(false);
  SetRelease(true);

#ifdef _WIN32
  struct timeval tv;
  tv.tv_sec = 0;
  tv.tv_usec = 100000;
  select(0,NULL,NULL,NULL,&tv);
  ::CloseHandle(m_thread);
#else
  sleep(1);
#endif
}
}


threadfunc_t STDPREFIX Thread::StartThread(threadparam_t zz)
{
Thread *pclThread = (Thread *)zz;

while (pclThread -> m_running && !pclThread -> m_release)
{
#ifdef _WIN32
  struct timeval tv;
  tv.tv_sec = 0;
  tv.tv_usec = 100000;
  select(0,NULL,NULL,NULL,&tv);
#else
  sleep(1);
#endif
}
if (pclThread -> m_running)
{
  pclThread -> Run();
}
pclThread -> SetRunning(false);       // if return
return (threadfunc_t)zz;
}


bool Thread::IsRunning()
{
return m_running;
}


void Thread::SetRunning(bool x)
{
m_running = x;
}


bool Thread::IsReleased()
{
return m_release;
}


void Thread::SetRelease(bool x)
{
m_release = x;
}

转载于:https://www.cnblogs.com/hmmcsdd/archive/2007/12/03/aboutmangosmutlithreaddealmethod.html

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值