LUA Coroutine

由于我们伟大的策划要求在游戏脚本中支持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的内存消耗。客户端上没什么,在服务器端这是个需要权衡的地方。

时间: 2024-10-04 13:12:37

LUA Coroutine的相关文章

Lua、LuaJIT Coroutine和Ruby Fiber的切换效率对比

最近重读了<Programming Lua>,对协程做了重点复习.众所周知,Ruby1.9引入了Fiber,同样是coroutine,不过Ruby Fiber支持全对称协程(通过fiber库),而Lua只支持所谓半对称协程.     这里将对Lua.LuaJIT和Ruby Fiber的切换效率做个对比测试,测试场景很简单:两个coroutine相互切换达到5000万次,统计每秒切换的次数,各测试多次取最佳.     lua的程序如下:     c1=coroutine.create(funct

Lua之协同程序coroutine代码实例_Lua

do --create coroutine table --coroutine state: suspended, running, dead, normal --when create the coroutine, the status is suspended, After calling it, the status is dead --get the coroutine status by the way coroutine.status local coA = 0; local coB

How nginx &quot;location if&quot; works

Nginx's if directive does have some weirdness in practice. And people may misuse it when they do not have enough knowledge about its behavior. In this post, I'll analyze some examples here such that people may get some light and use it correctly. In

Lua中的协同程序 coroutine(转)

Lua中的协程和多线程很相似,每一个协程有自己的堆栈,自己的局部变量,可以通过yield-resume实现在协程间的切换.不同之处是:Lua协程是非抢占式的多线程,必须手动在不同的协程间切换,且同一时刻只能有一个协程在运行.并且Lua中的协程无法在外部将其停止,而且有可能导致程序阻塞.   协同程序(Coroutine): 三个状态:suspended(挂起,协同刚创建完成时或者yield之后).running(运行).dead(函数走完后的状态,这时候不能再重新resume). corouti

LUA 协程 Coroutine

协程 Coroutine 协程(coroutine)并不是 Lua 独有的概念,如果让我用一句话概括,那么大概就是:一种能够在运行途中主动中断,并且能够从中断处恢复运行的特殊函数.(嗯,其实不是函数.) 举个最原始的例子: 下面给出一个最简单的 Lua 中 coroutine 的用法演示: function greet() print "hello world" end co = coroutine.create(greet) -- 创建 coroutine print(corouti

Lua协同程序(COROUTINE)运行步骤分解_Lua

这是一段分析 lua 协程(协同程序,coroutine)的代码,来自 Lua reference manual interface (略有修改): 复制代码 代码如下: function foo (a)     print("foo", a)     return coroutine.yield(2*a) end co = coroutine.create(function (a,b)    print("co-body1", a, b)    local r =

Lua的协程(coroutine)简介_Lua

协程和多线程下的线程类似:有自己的堆栈,自己的局部变量,有自己的指令指针,但是和其他协程程序共享全局变量等信息.线程和协程的主要不同在于:多处理器的情况下,概念上来说多线程是同时运行多个线程,而协程是通过协作来完成,任何时刻只有一个协程程序在运行.并且这个在运行的协程只有明确被要求挂起时才会被挂起 你可以使用coroutine.create来创建协程: 复制代码 代码如下: co = coroutine.create(function ()      print("hi") end)

Lua协同程序函数coroutine使用实例_Lua

协程是协同程序的简称,顾名思义,就是协同工作的程序.协程拥有自己独立的桟.局部变量和PC计数器,同时又与其他协同程序共享全局变量和其他大部分东西: 协程与线程的主要区别在于,一个多线程程序可以同时运行几个线程(并发执行.抢占),而协同程序却需要彼此协作地运行,即一个多协程程序在任意时刻只能运行一个协程,并且正在执行的协程只会在其显式地要求挂起(suspend)时,它的执行才会暂停(无抢占.无并发).  Lua中所有与协程相关的函数都在coroutine(一个table)中: 函数create用于

Lua协程(coroutine)程序运行分析_Lua

这是一段分析 lua 协程(协同程序,coroutine)的代码,来自 Lua reference manual interface (略有修改): 复制代码 代码如下: function foo (a)     print("foo", a)     return coroutine.yield(2*a) end co = coroutine.create(function (a,b)    print("co-body1", a, b)    local r =