牵着老婆满街逛

严以律己,宽以待人. 三思而后行.
GMail/GTalk: yanglinbo#google.com;
MSN/Email: tx7do#yahoo.com.cn;
QQ: 3 0 3 3 9 6 9 2 0 .

LUA Coroutine

转载自:http://hyperiris.spaces.live.com/blog/cns!D9CFE2DC046098F8!587.entry
作者:hyperiris

由于我们伟大的策划要求在游戏脚本中支持system.wait_second(20) 这样的功能,于是确定实现的方法成了一个需要解决的问题。众多前辈指出,使用LUA Coroutine可以达到我们的要求,可是我在LUA这块可以说是一窍不通,只好硬着头皮强上了。

听说《游戏编程精粹5》有一篇文章不错,我就把文章看了一遍,把光盘上的代码弄下来Compile,嘿,果然不错。

问题就这么轻松的解决了?NO!

我继续试验,从原代码的3个Coroutine增加到100个,程序马上就挂了,有各种奇怪的错误,什么stack overflow等等……

最关键的是,由lua_newthread出来的state奇怪的消失了。原来的创建代码如下:

LUASCRIPT::LUASCRIPT( LUAMANAGER*     mgr)
{
    manager             
= mgr;
    state               
= LSS_NOTLOADED;
    time             
= 0;
    strcpy(lastErrorString, 
"No error.\n"); 

    
// create a thread/state for this object
    threadState = lua_newthread(manager->masterState);
    
// save a pointer to the thread manager object in the global table
    
// using the new thread's vm pointer as a key
    lua_pushlightuserdata(manager->masterState, threadState);
    lua_pushlightuserdata(manager
->masterState, this );
    lua_settable(manager
->masterState, LUA_GLOBALSINDEX );
}
 


这里隐含着一个严重的Bug,lua_pushlightuserdata其实是一个很RAW的API,换句话说,它并不知道你push的是什么。表面上看来,threadState被放在了表里面,也就有了引用不会被自动回收,实际上表里面存的只是一个RAW c pointer!当LUA觉得需要GC的时候,可怜的threadState就被回收了,于是整个程序就crash了。

改起来很简单:

    //lua_pushlightuserdata(manager->masterState, threadState);
    lua_pushthread(threadState);  //换成这个
    lua_pushlightuserdata(manager->masterState, this );
    lua_settable(manager
->masterState, LUA_GLOBALSINDEX ); 

原书代码中还有几处类似的错误,还有导致stack不平衡的代码,大家看《游戏编程精粹5》的时候,不可不信,不可全信啊。

另外,Coroutine好用,但是不是没有代价的,每次lua_newthread出来一个新的thread state,需要大约4K的内存消耗。客户端上没什么,在服务器端这是个需要权衡的地方。

posted on 2008-10-28 07:42 杨粼波 阅读(2557) 评论(2)  编辑 收藏 引用

评论

# re: LUA Coroutine[未登录] 2010-11-09 10:55 pass86

泪流满面,我也遇到同样的问题,也是怀疑被垃圾回收了,搜了下,哈哈,幸运。  回复  更多评论   

# re: LUA Coroutine 2011-09-23 11:05 观察者

我用了楼主的代码好像直接就崩溃了  回复  更多评论   


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