• 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状态的

  • 相关阅读:
    敏捷个人手机应用:如何下载敏捷个人资料
    2014年8月10日:敏捷个人奥森跑步+慢走分享
    敏捷个人手机应用:如何进行敏捷个人练习
    敏捷个人新体系:定位
    任何社区,只要能影响他人成长的人,都可以成为敏捷个人的荣誉会员
    亲密爱人:《亲密关系》读书笔记
    亲密爱人:《亲密关系
    2014.7.12 敏捷个人奥森健步走&敏友分享会.活动报道
    开放产品开发(OPD):产品负责人的工作原则和方法
    #敏捷个人资料# 免费下载 《敏捷个人-认识自我,管理自我 v0.8.pdf》
  • 原文地址:https://www.cnblogs.com/still-smile/p/14819470.html
Copyright © 2020-2023  润新知