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的内存消耗。客户端上没什么,在服务器端这是个需要权衡的地方。

目录
打赏
0
0
0
0
96
分享
相关文章
LUA 协程 Coroutine
协程 Coroutine 协程(coroutine)并不是 Lua 独有的概念,如果让我用一句话概括,那么大概就是:一种能够在运行途中主动中断,并且能够从中断处恢复运行的特殊函数。(嗯,其实不是函数。
2578 0
【📕分布式锁通关指南 03】通过Lua脚本保证redis操作的原子性
本文介绍了如何通过Lua脚本在Redis中实现分布式锁的原子性操作,避免并发问题。首先讲解了Lua脚本的基本概念及其在Redis中的使用方法,包括通过`eval`指令执行Lua脚本和通过`script load`指令缓存脚本。接着详细展示了如何用Lua脚本实现加锁、解锁及可重入锁的功能,确保同一线程可以多次获取锁而不发生死锁。最后,通过代码示例演示了如何在实际业务中调用这些Lua脚本,确保锁操作的原子性和安全性。
102 6
【📕分布式锁通关指南 03】通过Lua脚本保证redis操作的原子性
Redis 功能扩展 Lua 脚本 对Redis扩展 eval redis.call redis.pcall
通过本文的介绍,我们详细讲解了 Lua 脚本在 Redis 中的作用、`eval` 命令的使用方法以及 `redis.call` 和 `redis.pcall` 的区别和用法。通过合理使用 Lua 脚本,可以实现复杂的业务逻辑,确保操作的原子性,并减少网络开销,从而提高系统的性能和可靠性。
96 13
|
4月前
|
公司用什么软件监控电脑:Lua 脚本在监控软件扩展功能的应用
在企业环境中,电脑监控软件对保障信息安全、提升效率至关重要。Lua 脚本在此类软件中用于扩展功能,如收集系统信息、监控软件使用时长及文件操作,向指定服务器发送数据,支持企业管理和运营。
73 6
Redis系列学习文章分享---第六篇(Redis实战篇--Redis分布式锁+实现思路+误删问题+原子性+lua脚本+Redisson功能介绍+可重入锁+WatchDog机制+multiLock)
Redis系列学习文章分享---第六篇(Redis实战篇--Redis分布式锁+实现思路+误删问题+原子性+lua脚本+Redisson功能介绍+可重入锁+WatchDog机制+multiLock)
307 0
大数据-43 Redis 功能扩展 Lua 脚本 对Redis扩展 eval redis.call redis.pcall
大数据-43 Redis 功能扩展 Lua 脚本 对Redis扩展 eval redis.call redis.pcall
70 2
如何使用 Lua 脚本进行更复杂的网络请求,比如 POST 请求?
如何使用 Lua 脚本进行更复杂的网络请求,比如 POST 请求?
AI助理

你好,我是AI助理

可以解答问题、推荐解决方案等