lua5.4 coroutine的通俗理解

摘要:
官方文档中的解释针对目前的lua5.4,官方api中对coroutine的解释如下函数名参数返回值作用coroutine.createfunctionthread创建一个主体函数为f的新协程。coroutine.isyieldablethreadboolean如果协程co可以让出,则返回真。coroutine.closethreadbooleannoerroranyerrorobject关闭协程co,并关闭它所有等待to-be-closed的变量,并将协程状态设为dead。coroutine.resumethreadanyboolean,any开始或继续协程co的运行。coroutine.statusthreadstring:"running"正在运行;"suspended"挂起或是还没有开始运行;"normal"是活动的,但并不在运行;"dead"行完主体函数或因错误停止。coroutine.running()voidthread,boolean返回当前正在运行的协程加一个布尔量。*/#defineTValuefieldsValuevalue_;lu_bytett_typedefstructTValue{TValuefields;}TValue;/***Lua堆栈中的条目。

官方文档中的解释

针对目前的lua5.4,官方api中对coroutine的解释如下

函数名参数返回值作用
coroutine.create(f)functionthread创建一个主体函数为 f 的新协程。 f 必须是一个 Lua 的函数。 返回这个新协程,它是一个类型为 "thread" 的对象。
(对应函数:luaB_cocreate)
coroutine.isyieldable(co)threadboolean如果协程 co 可以让出,则返回真。co 默认为正在运行的协程。
coroutine.close(co)threadboolean noerror
any errorobject
关闭协程 co,并关闭它所有等待 to-be-closed 的变量,并将协程状态设为 dead
coroutine.resume(co, val1, ...)thread
any
boolean,any开始或继续协程 co 的运行。
(对应函数:luaB_coresume)
coroutine.status(co)threadstring:
"running"正在运行;
"suspended"挂起或是还没有开始运行;
"normal"是活动的,但并不在运行;
"dead"行完主体函数或因错误停止。
以字符串形式返回协程 co 的状态。
coroutine.wrap(f)functionfun(...):...创建一个主体函数为 f 的新协程。 f 必须是一个 Lua 的函数。 返回一个函数, 每次调用该函数都会延续该协程。
coroutine.running()voidthread,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状态的

免责声明:文章转载自《lua5.4 coroutine的通俗理解》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇malloc原理和内存碎片Windows SC命令详解下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

Java之协程(quasar)

  一、前面我们简单的说了一下,Python中的协程原理。这里补充Java的协程实现过程。有需要可以查看python之协程。   二、Java协程,其实做Java这么久我也没有怎么听过Java协程的东西,但是一直有有听到微线程/协程的概念,这不在学习Python的时候接触到了协程一词。然后返回来去了解Java的协程问题,但是看了很多资料,发现官网以及很多地...

unity 协程与async、await

协程(Coroutine) 协程就像一个函数,能够暂停执行并将控制权返还给 Unity,然后在指定的时间继续执行。协程本质上是一个用返回类型 IEnumerator 声明的函数,并在主体中的某个位置包含 yield return 语句。yield return 是暂停执行并随后在下一个时间点恢复。注意:Fade 函数中的循环计数器能够在协程的生命周期内保持...

LaravelS

LaravelS LaravelS是一个胶水项目,用于快速集成Swoole到Laravel或Lumen,然后赋予它们更好的性能、更多可能性。Github 特性 内置Http/WebSocket服务器 多端口混合协议 协程 自定义进程 常驻内存 异步的事件监听 异步的任务队列 毫秒级定时任务 平滑Reload 修改代码后自动Reload 同时支持Lar...

使用python asyncio+aiohttp做接口测试(TODO)

线程是操作系统层面的“并行”, 协程是应用程序层面的“并行”。 协程本质上就是:提供一个环境,保存一些需要等待的任务,当这些任务可以执行(等待结束)的时候,能够执行。再等待的过程中,程序可以执行别的任务。 asyncio是python3.4版本引入到标准库因此要注意python版本 我的python环境 Python 3.6.5 (v3.6.5:f59c0...

c#协程的基本用法

C#协程的用法。 协程:协同程序,在主程序运行的同时,开启另外一段逻辑处理,来协同当前程序的执行,。 开启协程的两种方式 1、StartCoroutine(string methodName) 注意: (1)、参数是方法名(字符串类型),此方法可以包含一个参数 (2)、形参方法可以有返回值 2、StartCoroutine(IEnumerator met...

Python与Golang协程异同

背景知识 这里先给出一些常用的知识点简要说明,以便理解后面的文章内容。 进程的定义: 进程,是计算机中已运行程序的实体。程序本身只是指令、数据及其组织形式的描述,进程才是程序的真正运行实例。 线程的定义: 操作系统能够进行运算调度的最小单位。它被包含在进程之中,是进程中的实际运作单位。 进程和线程的关系: 一条线程指的是进程中一个单一顺序的控制流,一个进程...