lua协程实现简析
协程,简单来说就是新创建一个协助程序(co = coroutine.create(func)),然后需要手动去启动它(coroutine.resume(co)),在它最终退出之前,它有可能暂停多次返回阶段性的结果(coroutine.yield(co)),每一次暂停之后都必须手动去恢复它(coroutine.resume(co))。
协程在lua源文件中对应lcorolib.c,数组co_funcs中定义了c暴露给lua的接口。从上面的描述看和c函数调用有点相似,只不过c函数只有一个出口,所以不可能返回多次。题外话,为什么c函数只有一个出口?我自己粗浅的理解是因为c函数的所有信息都放在栈上,而c语言没有提供原生的保存/恢复栈空间的支持,所以没有中途退出后还能生新进入这个概念。实际上,协程和系统级别的进程切换更像一点,都是保存堆栈,然后恢复。我想最大的不同就是协程知道接下来的控制权在哪里,而进程不知道。根本上它们想实现的功能就不一样吧。
好了,那协程实现的要点就是堆栈的保存与恢复了。当然,这里的堆栈不是进程本身的堆栈,而是lua的soft stack。从代码上来说吧:
static int luaB_cocreate (lua_State *L) {
lua_State *NL;
luaL_checktype(L, , LUA_TFUNCTION);
NL = lua_newthread(L);
lua_pushvalue(L, ); /* move function to top */
lua_xmove(L, NL, ); /* move function from L to NL */
return ;
}
其中NL就是新创建的协程的栈,以后所有的保存/恢复都是针对这个栈。lua_State这个结构体里对协程实现最重要的是CallInfo *ci,CallInfo的定义如下:
/*
67 ** information about a call
68 */
typedef struct CallInfo {
StkId func; /* function index in the stack */
StkId top; /* top for this function */
struct CallInfo *previous, *next; /* dynamic call link */
short nresults; /* expected number of results from this function */
lu_byte callstatus;
ptrdiff_t extra;
union {
struct { /* only for Lua functions */
StkId base; /* base for this function */
const Instruction *savedpc;
} l;
struct { /* only for C functions */
int ctx; /* context info. in case of yields */
lua_CFunction k; /* continuation in case of yields */
ptrdiff_t old_errfunc;
lu_byte old_allowhook;
lu_byte status;
} c;
} u;
} CallInfo;
其中func指向当前调用的函数在栈上的位置,而savedpc就是保存的指令执行位置(先无视union里的c),根据这两个值就能恢复函数的执行点。然而在yield的时候真正负责保存函数位置的是extra(保存func与栈顶的相对位置),在resume时func会根据extra来恢复,有没有这个需要我是表示怀疑的,因为就算resume传递的参数导致栈realloc,使func失效,但在luaD_reallocstack内会调用correctstack将调用链上所有的func重新设置为正确的值,所以这里是不是多余的呢?
在lua 5.2中调用路径包含c函数的时候也能够进行yield,只不过不甚好看。由于c函数不能保存堆栈,所以lua的策略是直接放弃当前c函数的栈幀,而让调用者本身提供一个continuation,当resume时调用上面被无视的uion里的c.k。没用过,所以也不深入考究了。
lua协程实现简析的更多相关文章
- Lua 协程coroutine
协程和一般多线程的区别是,一般多线程由系统决定该哪个线程执行,是抢占式的,而协程是由每个线程自己决定自己什么时候不执行,并把执行权主动交给下一个线程. 协程是用户空间线程,操作系统其存在一无所知,所以 ...
- [转]-Lua协程的实现
协程是个很好的东西,它能做的事情与线程相似,区别在于:协程是使用者可控的,有API给使用者来暂停和继续执行,而线程由操作系统内核控制:另 外,协程也更加轻量级.这样,在遇到某些可能阻塞的操作时,可以使 ...
- LUA 协程
LUA协程和C#协程非常相似,功能与用法更强大.基础用法: coco = coroutine.create(function (a,b) print("resume args:". ...
- lua 协程的理解
参考链接: http://www.cnblogs.com/zrtqsk/p/4374360.html 对例子的自我理解: -- 协程的理解 -- co 是协程的内容,类似函数内容, 通过yield 将 ...
- Lua协程-测试3
print("Lua 协程测试3") -- 实现消费者-生产者关系(生产一个就消费一个) count = -- 生产总数 -- 生产者 local newProductorCo = ...
- Lua协程-测试2
print("Lua 协程测试2") function testFun(n) print("into foo,n = "..n) * n) -- 挂起co协程 ...
- lua协程实现
协程是个很好的东西,它能做的事情与线程相似,区别在于:协程是使用者可控的,有API给使用者来暂停和继续执行,而线程由操作系统内核控制:另外,协程也更加轻量级.这样,在遇到某些可能阻塞的操作时,可以使用 ...
- 大富翁开发日记:一、使用巨型lua协程
一个大胆的尝试:使用巨型lua协程来表示整个“一局”流程. lua协程是一个很另类的功能,有并发的影子但又不是真的并发,所以真正拿它来做大功能框架的范例不多,通常用于一些小型trick式设计.但这次我 ...
- Lua 协程和线程区别
协程就是协程,不是线程. CPU执行单位是线程,不是什么协程. 协程,是同步执行,不是并行,只是切了一个上下文了,为你保存原来的上下文而已. 切到第二个协程时,原来的协程处于挂起状态. 这个特指lua ...
随机推荐
- CF 369 B. Valera and Contest
http://codeforces.com/contest/369/problem/B 题意 :n, k, l, r, sall, sk,n代表的是n个人,这n个人的总分是sall,每个人的得分大于 ...
- 【mysql的设计与优化专题(2)】数据中设计中的范式与反范式
设计关系数据库时,遵从不同的规范要求,设计出合理的关系型数据库,这些不同的规范要求被称为不同的范式,各种范式呈递次规范,越高的范式数据库冗余越小.但是有些时候一昧的追求范式减少冗余,反而会降低数据读写 ...
- 基于ASP.NET的comet简单实现
http://www.cnblogs.com/hanxianlong/archive/2010/04/27/1722018.html 我潜水很多年,今天忽然出现.很久没写过博客了,不是因为不想写,而是 ...
- WPF之监听组合键事件
private void KeyDown(object sender, KeyEventArgs e) { if (e.Key== Key.Up && Keyboard.Modifie ...
- java去除重复的字符串和移除不想要的字符串
在java开发中碰到了有些字符串是重复的,如果在进行业务处理要全部遍历太对的数据就会重复,所以在进行业务处理前进行一个去重操作. 这里由于业务需要所以先将字符串转化为string数组,使用split分 ...
- Why it is good practice to declare loggers private, static, and final?
// Jakarta Commons Loggingprivate static final Log log = LogFactory.getLog(MyClass.class);The above ...
- strcat与strncat的C/C++实现
2013-07-05 15:47:19 本函数给出了几种strcat与strncat的实现,有ugly implementation,也有good implementation.并参考标准库中的imp ...
- android 电容屏(一):电容屏基本原理篇
平台信息: 内核:linux3.4.39系统:android4.4 平台:S5P4418(cortex a9) 作者:瘋耔(欢迎转载,请注明作者) 欢迎指正错误,共同学习.共同进步!! 关注博主新浪博 ...
- C#.Net 如何动态加载与卸载程序集(.dll或者.exe)6-----在不卸载程序域的前提下替换程序集文件。
当某个程序集文件被载入AppDomain,该文件在AppDomain.Unload之前是不能被替换和删除的.使用AppDomainSetup的影像复制功能可以实现在不卸载程序的情况下替换或者删除程序集 ...
- Redpine Signals RS9110-N-11-02 Wi-Fi解决方案
Redpine Signals公司的RS9110-N-11-02是兼容IEEE 802.11bgn的Wi-Fi客户端模块,集成了MAC,基带处理器,RF收发器和功率放大器.和RS9110-LI MAC ...