local co = coroutine.create(function() print("hi") end)
print(co) --output: thread: 0038BEE0 准确来说,协程是一个线程外加一套良好的操作接口。lua_State *lua_newstate (lua_Alloc f, void *ud);没错,在应用程序(比如用C++编写的)中,为了加载和执行Lua脚本,首先要调用的函数就是这个函数来初始化虚拟机。该函数在初始化虚拟机状态的同时,还是创建整个虚拟机的第一个线程(称为主线程),或者说是第一个交互栈。为了在已经初始化的全局状态中创建一个新的线程(或交互栈)可以调用函数lua_newthread,该函数声明如下:
lua_State *lua_newthread (lua_State *L);创建一个线程就拥有一个独立的执行栈了,但是它与其线程共用虚拟机的全局状态。Lua中没有函数去close或destroy 一个线程,创建的线程类型数据与其他GC对象一样,由虚拟机来管理销毁。
总之,一个Lua虚拟机只有一个全局的状态,但可以包含多个执行环境(或者说多个线程、交互栈,从脚本角度来说,也可以说是多个协程),也就是说多个执行环境共享一个全局状态。如下图所示:
下面将通过Lua 5.2.1的源码来看全局状态的数据结构global_State和脚本执行的相关的上下文环境结构lua_State,以及函数lua_newstate和lua_newthread的实现。
2、源码实现
首先来分析全局状态的结构体global_State的代码(lstate.h):
109 /*
110 ** `global state', shared by all threads of this state
111 */
112 typedef struct global_State {
113 lua_Alloc frealloc; /* function to reallocate memory */
114 void *ud; /* auxiliary data to `frealloc' */
115 lu_mem totalbytes; /* number of bytes currently allocated - GCdebt */
116 l_mem GCdebt; /* bytes allocated not yet compensated by the collector */
117 lu_mem GCmemtrav; /* memory traversed by the GC */
118 lu_mem GCestimate; /* an estimate of the non-garbage memory in use */
119 stringtable strt; /* hash table for strings */
120 TValue l_registry;
121 unsigned int seed; /* randomized seed for hashes */
122 lu_byte currentwhite;
123 lu_byte gcstate; /* state of garbage collector */
124 lu_byte gckind; /* kind of GC running */
125 lu_byte gcrunning; /* true if GC is running */
126 int sweepstrgc; /* position of sweep in `strt' */
127 GCObject *allgc; /* list of all collectable objects */
128 GCObject *finobj; /* list of collectable objects with finalizers */
129 GCObject **sweepgc; /* current position of sweep in list 'allgc' */
130 GCObject **sweepfin; /* current position of sweep in list 'finobj' */
131 GCObject *gray; /* list of gray objects */
132 GCObject *grayagain; /* list of objects to be traversed atomically */
133 GCObject *weak; /* list of tables with weak values */
134 GCObject *ephemeron; /* list of ephemeron tables (weak keys) */
135 GCObject *allweak; /* list of all-weak tables */
136 GCObject *tobefnz; /* list of userdata to be GC */
137 UpVal uvhead; /* head of double-linked list of all open upvalues */
138 Mbuffer buff; /* temporary buffer for string concatenation */
139 int gcpause; /* size of pause between successive GCs */
140 int gcmajorinc; /* how much to wait for a major GC (only in gen. mode) */
141 int gcstepmul; /* GC `granularity' */
142 lua_CFunction panic; /* to be called in unprotected errors */
143 struct lua_State *mainthread;
144 const lua_Number *version; /* pointer to version number */
145 TString *memerrmsg; /* memory-error message */
146 TString *tmname[TM_N]; /* array with tag-method names */
147 struct Table *mt[LUA_NUMTAGS]; /* metatables for basic types */
148 } global_State;一个Lua虚拟机只有一个全局的global_State,在调用lua_newstate时候,会创建和初始化这个全局结构,这个全局结构管理着lua中全局唯一的信息, 主要包括以下信息:151 /*
152 ** `per thread' state
153 */
154 struct lua_State {
155 CommonHeader;
156 lu_byte status;
157 StkId top; /* first free slot in the stack */
158 global_State *l_G;
159 CallInfo *ci; /* call info for current function */
160 const Instruction *oldpc; /* last pc traced */
161 StkId stack_last; /* last free slot in the stack */
162 StkId stack; /* stack base */
163 int stacksize;
164 unsigned short nny; /* number of non-yieldable calls in stack */
165 unsigned short nCcalls; /* number of nested C calls */
166 lu_byte hookmask;
167 lu_byte allowhook;
168 int basehookcount;
169 int hookcount;
170 lua_Hook hook;
171 GCObject *openupval; /* list of open upvalues in this stack */
172 GCObject *gclist;
173 struct lua_longjmp *errorJmp; /* current error recover point */
174 ptrdiff_t errfunc; /* current error handling function (stack index) */
175 CallInfo base_ci; /* CallInfo for first level (C calling Lua) */
176 };
可以看到,lua_State结构跟其他可回收的数据类型类型,结构体带用CommonHeader的头,它也GC回收的对象之一。它主要包括以下成员信息:
lu_byte status:线程脚本的状态,线程可能状态如下(lua.h):
44 /* thread status */ 45 #define LUA_OK 0 46 #define LUA_YIELD 1 47 #define LUA_ERRRUN 2 48 #define LUA_ERRSYNTAX 3 49 #define LUA_ERRMEM 4 50 #define LUA_ERRGCMM 5 51 #define LUA_ERRERR 6global_State *l_G:指向全局状态;
3、总结
在调用lua_newstate 初始化Lua虚拟机时,会创建一个全局状态和一个线程(或称为调用栈),这个全局状态在整个虚拟机中是唯一的,供其他线程共享。一个Lua虚拟机中可以包括多个线程,这些线程共享一个全局状态,线程之间也可以调用lua_xmove函数来交换数据。
参考资料
http://www.cnblogs.com/ringofthec/archive/2010/11/09/lua_State.html lua API 小记3(lua虚拟机初始化)
http://blog.aliyun.com/795 Lua数据结构 — lua_State(六)
Lua 5.2.1源码
原文:http://blog.csdn.net/maximuszhou/article/details/46277695