lua5.4 coroutine的通俗理解
官方文档中的解释
针对目前的lua5.4,官方api中对coroutine的解释如下
函数名 | 参数 | 返回值 | 作用 |
---|---|---|---|
coroutine.create(f) | function | thread | 创建一个主体函数为 f 的新协程。 f 必须是一个 Lua 的函数。 返回这个新协程,它是一个类型为 "thread" 的对象。(对应函数:luaB_cocreate) |
coroutine.isyieldable(co) | thread | boolean | 如果协程 co 可以让出,则返回真。co 默认为正在运行的协程。 |
coroutine.close(co) | thread | boolean noerror any errorobject |
关闭协程 co ,并关闭它所有等待 to-be-closed 的变量,并将协程状态设为 dead 。 |
coroutine.resume(co, val1, ...) | thread any |
boolean,any | 开始或继续协程 co 的运行。(对应函数:luaB_coresume) |
coroutine.status(co) | thread | string: "running"正在运行; "suspended"挂起或是还没有开始运行; "normal"是活动的,但并不在运行; "dead"行完主体函数或因错误停止。 |
以字符串形式返回协程 co 的状态。 |
coroutine.wrap(f) | function | fun(...):... | 创建一个主体函数为 f 的新协程。 f 必须是一个 Lua 的函数。 返回一个函数, 每次调用该函数都会延续该协程。 |
coroutine.running() | void | thread,boolean | 返回当前正在运行的协程加一个布尔量。 如果当前运行的协程是主线程,其为真。 |
coroutine.yield(...) | ... | ... | 挂起正在调用的协程的执行。 (对应函数:luaB_yield) |
create最简单的写法就是
mythread = coroutine.create(function()
print("hello wzh")
end)
lua中的create是通过luaB_cocreate()来创建的
//lcorolib.c 95行
static int luaB_cocreate (lua_State *L) {
lua_State *NL;//创建一个新的协程栈
luaL_checktype(L, 1, LUA_TFUNCTION);//检查传入的参数是否为函数,如果不是函数就会停止整个lua虚拟机的执行
NL = lua_newthread(L); /* new一个新协程 */
lua_pushvalue(L, 1); /* move function to top */
lua_xmove(L, NL, 1); /* move function from L to NL */
return 1;
}
create第一件事
主要做三件事,首先就是创建一个新的协程栈,协程栈主要包含
//lstate.h 303行
struct lua_State {
CommonHeader;
lu_byte status; //当前状态
lu_byte allowhook; //是否允许hook
unsigned short nci; /* number of items in 'ci' list */
StkId top; /* first free slot in the stack */
global_State *l_G;
CallInfo *ci; /* call info for current function */
StkId stack_last; /* end of stack (last element + 1) */
StkId stack; /* stack base */
UpVal *openupval; /* list of open upvalues in this stack */
StkId tbclist; /* list of to-be-closed variables */
GCObject *gclist;
struct lua_State *twups; /* list of threads with open upvalues */
struct lua_longjmp *errorJmp; /* current error recover point */
CallInfo base_ci; /* CallInfo for first level (C calling Lua) */
volatile lua_Hook hook;
ptrdiff_t errfunc; /* current error handling function (stack index) */
l_uint32 nCcalls; /* number of nested (non-yieldable | C) calls */
int oldpc; /* last pc traced */
int basehookcount;
int hookcount;
volatile l_signalT hookmask;
};
CommonHeader是一个数据头,所有的 GCObject 都有这个相同的数据头,这个数据头是一个宏,
#define CommonHeader GCObject *next; lu_byte tt; lu_byte marked
所有的 GCObject 都用一个单向链表串了起来。每个对象都以 tt 来识别其类型。marked 域用于标记清除的工作(也就是gc操作,gc操作两元色到三元色的演进,在我看来清楚了gc和协程就lua就基本掌握的差不多了)。
lu_byte status;
/* thread status 有六种*/
#define LUA_OK 0
#define LUA_YIELD 1
#define LUA_ERRRUN 2
#define LUA_ERRSYNTAX 3
#define LUA_ERRMEM 4
#define LUA_ERRERR 5
allowhook是否允许hook的意思,在源码中,暂时只找到两个数值0和1,目前对hook的理解就是类似中断的一种机制
allowhook = 0; /* cannot call hooks inside a hook */
allowhook = 0; /* stop debug hooks during GC metamethod */
allowhook = 1; //允许hook
nci指的是ci列表中的条目数,ci指的是?
unsigned short nci; /* number of items in 'ci' list */
堆栈中的第一个空闲槽
StkId top; /* first free slot in the stack */
StkId在lobject.h中有定义
/*
** 标记的值。 这是Lua中值的基本表示形式:实际值以及带有其类型的标记。
*/
#define TValuefields Value value_; lu_byte tt_
typedef struct TValue {
TValuefields;
} TValue;
/*
** Lua堆栈中的条目。 字段“ tbclist”构成了此堆栈中所有活动的将要关闭的变量的列表。
** 当两个tbc变量之间的距离不适合无符号短型时,将使用虚拟条目。
** 它们用delta == 0表示,其实际delta始终是该字段中适合的最大值。
*/
typedef union StackValue {
TValue val;
struct {
TValuefields;
unsigned short delta;
} tbclist;
} StackValue;
/* 第一个自由索引堆栈中的元素槽 */
typedef StackValue *StkId;
针对上述的Value其实是一个联合体,这个是lua中最为特别的联合体,被称为lua数据原子,用来完成绝大部分数据存储,第一种为可gc的对象,下面的四种为不需要gc
typedef union Value {
struct GCObject *gc; /* 可收集的对象 */
void *p; /* light userdata */
lua_CFunction f; /* light C functions 6*/
lua_Integer i; /* integer numbers */
lua_Number n; /* float numbers */
} Value;
从源码看的话lua中的数据类型一共有10种,第十种是啥有点看不懂,等遇到了就知道了,不过这种基本数据类型的设计有点迷,
#define LUA_TNONE (-1) //判断这个变量是否等于为空使用的,这个是Lua内部使用
#define LUA_TNIL 0 //全局变量没被赋值默认为nil,删除变量就赋值为 nil
#define LUA_TBOOLEAN 1 //布尔值
#define LUA_TLIGHTUSERDATA 2 //自定义类型,需要自己管理分配和回收,相关函数lua_pushlightuserdata()
#define LUA_TNUMBER 3 // 实数
#define LUA_TSTRING 4 //字符串
#define LUA_TTABLE 5 //数组,表
#define LUA_TFUNCTION 6 //函数
#define LUA_TUSERDATA 7 //自定义类型,是由LUA的GC机制进行回收,相关函数lua_newuserdata()
#define LUA_TTHREAD 8 //线程协程,相关函数lua_newthread,lua_newstate
#define LUA_NUMTYPES 9 //
create第二件事
就是将CallInfo操作栈上的协程回调函数,移动到L->top数据栈顶部
lua_pushvalue(L, 1);
create第三件事
就是将拷贝回调函数到协程的数据栈上
lua_xmove(L, NL, 1);
调用create后的协程是suspended状态的