lua5.1学习笔记(一)

来源:互联网 发布:农业追溯软件 编辑:程序博客网 时间:2024/05/18 03:18

一:  lua协同程序

1 : 关于coroutine.resume(co, ...)和coroutine.yield(xxx)两个函数的参数和返回值

1.1:  如果coroutine.resume(co, ...)调用失败。print(coroutine.resume(co, ...))  打印 false;如果是第一次调用resume,除了第一个参数以外,resume调用的其余参数值都视为给协同程序的主函数传递参数。比如coroutine.resume(co,  1,2,3)相当于给协同程序的主函数传递了1,2,3这三个int类型的参数值。

        1.2:如果coroutine.resume(co, ...)调用成功。coroutine.resume(co, ...)则有可能出现两种返回值:请看以下<coro.lua>例子:

local co = coroutine.create(function (...)
    print("arg: ", ...)
    print("yield return: ", coroutine.yield("coroutine stop", ...))
    print("restart coroutine:", ...)
    return "coroutine end"
end)
print("resume 1: ", coroutine.resume(co, 1, 2, 3)) 
print("resume
 2: ", coroutine.resume(co, 4, 5, 6,"restart"))

运行lua coro.lua的结果如下:

[root@localhost testLua]# lua coro.lua 
arg:    1       2       3
resume 1:       true    coroutine stop  1       2       3
yield return:   4       5       6       restart
restart coroutine:      1       2       3
resume 2:       true    coroutine end

从coro.lua的运行结果可以看出来:

第一,coroutine.resume遇到协同程序主函数的coroutine.yield的时候,主函数处于挂起状态,resume的返回值是:true 后加 coroutine.yield的参数。

第二,coroutine.resume调用遇到协同程序主函数结束的时候,主函数运行结束。resume的返回值是:true后加主函数的return值。

从coro.lua的例子也可以看出来coroutine.yield()函数的运行机制:

第一:主函数第一次运行到coroutine.yield函数的时候,主函数挂起;coroutine.yield并不返回任何值,仅仅是存储下了resume传递的参数。

第二:coroutine.resume(co, 4, 5, 6,"restart")再次启动主函数的时候,主函数继续运行,coroutine.yield有返回值,返回值是本次resume传递的参数值。

第三:coroutine.resume(co, 4, 5, 6,"restart")再次启动主函数的时候,主函数接着往下运行,但是本次resume传递的参数值,并不影响主函数的后续执行结果。也就是说,主函数coroutine.yield往后的代码执行结果取决于第一次resume传递的参数。所以print("restart coroutine:", ...)的运行结果是:

restart coroutine:      1       2       3


2:关于c API lua_resume于Lua交互的栈结果,请看以下lua程序foo.lua和c++程序lua_resume_test.cpp

<foo.lua>

function Func2(value)

print("Func2 begin.")

   coroutine.yield(5, value + 10,value+20,value+30)

    print("Func2 ended.")
end


function Func1(param1)
    print("Func1 begin")
    Func2(param1 + 10) 
    print("Func1 ended.")
    return 100,"game over"
end


   <lua_resume_demo.cpp>

#include <iostream>
#include <lua.hpp>
#include <lualib.h>
#include <lauxlib.h>

using namespace std;

int main()
{
    //创建主线程
    lua_State *L = luaL_newstate();
    //打开lua辅助库
    luaL_openlibs(L);


    lua_State *L1 = lua_newthread(L);
    if (!L1)
    {
        return 0;
    }
    //L的栈顶是L1,thread类型的值
    cout << "L Element Num:" << lua_gettop(L)<<" " << lua_type(L,1) << endl;
    //在L1加载lua文件
    luaL_dofile(L1,"foo.lua");

lua_getglobal(L1, "Func1");

    lua_pushinteger(L1, 10);
    cout << "L1 Element Num:" << lua_gettop(L1) << endl;
    // 运行这个协同程序
    // // 这里返回LUA_YIELD
    int iRet = lua_resume(L1, 1);
    cout << "LUA_YIELD = " << LUA_YIELD << endl;
    cout << "iRet:" << iRet << endl;
    // // 打印L1栈中元素的总数
    cout << "Element Num:" << lua_gettop(L1) << endl;
    // 打印yield返回的四个值
    cout << "Value 1:" << lua_tointeger(L1, 1) << endl;
    cout << "Value 2:" << lua_tointeger(L1, 2) << endl;
    cout << "Value 3:" << lua_tointeger(L1, 3) << endl;
    cout << "Value 4:" << lua_tointeger(L1, 4) << endl;

    /// 再次启动协同程序
    /// 这里返回0
    iRet = lua_resume(L1, 0);
    cout << "iRet:" << iRet << endl;
    cout << "Element Num:" << lua_gettop(L1) << endl;
    cout << "Value 1:" << lua_tointeger(L1, -2) << endl;
    cout << "Value 1:" << lua_tostring(L1, -1) << endl;
    //关闭主线程
    lua_close(L);
    return 0;

}


[root@localhost testLua]# g++ -g lua_resume_demo.cpp -ldl -llua
[root@localhost testLua]# ./a.out 
L Element Num:1 8
L1 Element Num:2
Func1 begin
Func2 begin.
LUA_YIELD = 1
iRet:1
Element Num:4
Value 1:5
Value 2:30
Value 3:40
Value 4:50
Func2 ended.

Func1 ended.
iRet:0
Element Num:2
Value 1:100
Value 1:game over

  

上面的例子是C语言调用Lua代码,Lua可以自己挂起自己。lua_resume可以启动一个协同程序,它的用法就像lua_call一样。将待调用的函数压入栈中,并压入其参数,最后在调用lua_resume时传入参数的数量narg。这个行为与lua_pcall类似,但有3点不同。

  1. lua_resume没有参数用于指出期望的结果数量,它总是返回被调用函数的所有结果;
  2. 它没有用于指定错误处理函数的参数,发生错误时不会展开栈,这就可以在发生错误后检查栈中的情况;
  3. 如果正在运行的函数交出(yield)了控制权,lua_resume就会返回一个特殊的代码LUA_YIELD,并将线程置于一个可以被再次恢复执行的状态。

当lua_resume返回LUA_YIELD时,线程的栈中只能看到交出控制权时所传递的那些值。调用lua_gettop则会返回这些值的数量。为了恢复一个挂起线程的执行,可以再次调用lua_resume。在这种调用中,Lua假设栈中所有的值都是由yield调用返回的,当然了,你也可以任意修改栈中的值。

3:关于C API lua_yield的使用:

3.1编写调用lua_yield  API的c函数库lua_yield_demo.c:

#include <string.h>
#include <lua.h>
#include <lauxlib.h>
#include <lualib.h>


static int IsSet(lua_State *L) 
{
    lua_getfield(L, LUA_ENVIRONINDEX, "leisure");
    if (lua_isnil(L, -1))
    {   
        printf("Not set\n");
        return 0;
    }   
    printf("leisure is seted\n");
    return 1;

}

static int Func1(lua_State *L)
{
    if (!IsSet(L))
    {
        lua_pushinteger(L, 1000);
        printf("stack size:%d\n",lua_gettop(L));
        printf("Begin yield,end return 1000 to lua programme\n");
        return lua_yield(L, 1);
    }
    printf("Resumed again\n");
    lua_getfield(L, LUA_ENVIRONINDEX, "leisure");
    printf("stack size:%d\n",lua_gettop(L));
    return 1;

}
static int Func2(lua_State *L)
{
    printf("Func2 stack size:%d,stack value:%d\n",lua_gettop(L),lua_tointeger(L,1)
);
    luaL_checkinteger(L, 1);
    lua_pushvalue(L, 1);
    printf("Func2 stack size:%d,stack value:%d\n",lua_gettop(L),lua_tointeger(L,1)
);
    lua_setfield(L, LUA_ENVIRONINDEX, "leisure");
    printf("Func2 stack size:%d,stack value:%d\n",lua_gettop(L),lua_tointeger(L,1)
);
    return 0;
}

static luaL_Reg luayielddemo[] = {
    {"IsSet", IsSet},
    {"Func1", Func1},
    {"Func2", Func2},
    {NULL, NULL}
};


int luaopen_luayielddemo(lua_State* L)
{
    ///设置c模块环境表
    lua_newtable(L);
    printf("stack size:%d,%s,%s\n",lua_gettop(L),lua_tostring(L,1),lua_istable(L,2
)?"true":"false");
    lua_replace(L,LUA_ENVIRONINDEX);

 printf("stack size:%d,stack value:%s\n",lua_gettop(L),lua_tostring(L,1));
    ///注册c函数
    const char* libName = "luayielddemo";
    luaL_register(L,libName,luayielddemo);
    return 1;
}


生成动态库文件:gcc -g lua_yield_demo.c -fPIC -shared -o luayielddemo.so


3.2编写调用动态库luayielddemo.so的lua程序 luayield.lua

local Module = require"luayielddemo"
local function1 = function (a,b,c)
    local value
    repeat
        value = Module.Func1(a,b,c)
    until value
    return value
end
local thread1 = coroutine.create(function1)
print(coroutine.resume(thread1,1,2,3))
print(coroutine.status(thread1))
-- 设置C函数环境
Module.Func2(9999)
print(coroutine.resume(thread1,4,5,6))


3.3:运行luayield.lua程序

[root@localhost testLua]# lua luayield.lua 
stack size:2,luayielddemo,true
stack size:1,stack value:luayielddemo
Not set
stack size:5
Begin yield,end return 1000 to lua programme
true    1000
suspended
Func2 stack size:1,stack value:9999
Func2 stack size:2,stack value:9999
Func2 stack size:1,stack value:9999
true    4

3.4:通过结果可以看出来,C代码调用lua_yield不能让c程序停止运行,但是lua_yield可以让它的lua调用者挂起。

1 0
原创粉丝点击