skynet源码学习1-基础知识

1、skynet基础知识

1.1、lua源码获取

尝试着编译了一下lua的源码,源码地址如下:
http://www.lua.org/download.html

获取后先解压,解压后如下:

[zhu_shiyong1@hitry161 local]$ 
doc  Makefile  README  src

输入make linux test开始编译

部分编译信息如下:

[zhu_shiyong1@hitry161 lua-5.4.0]$ make linux test
make[1]: Entering directory `/home/zhu_shiyong1/lua-5.4.0/src'
make all SYSCFLAGS="-DLUA_USE_LINUX" SYSLIBS="-Wl,-E -ldl"
make[2]: Entering directory `/home/zhu_shiyong1/lua-5.4.0/src'
gcc -std=gnu99 -O2 -Wall -Wextra -DLUA_COMPAT_5_3 -DLUA_USE_LINUX    -c -o lapi.o lapi.c
gcc -std=gnu99 -O2 -Wall -Wextra -DLUA_COMPAT_5_3 -DLUA_USE_LINUX  -Os -c lcode.c
......
......
gcc -std=gnu99 -o lua   lua.o liblua.a -lm -Wl,-E -ldl 
gcc -std=gnu99 -O2 -Wall -Wextra -DLUA_COMPAT_5_3 -DLUA_USE_LINUX    -c -o luac.o luac.c
gcc -std=gnu99 -o luac   luac.o liblua.a -lm -Wl,-E -ldl 
make[2]: Leaving directory `/home/zhu_shiyong1/lua-5.4.0/src'
make[1]: Leaving directory `/home/zhu_shiyong1/lua-5.4.0/src'
make[1]: Entering directory `/home/zhu_shiyong1/lua-5.4.0/src'
./lua -v
Lua 5.4.0  Copyright (C) 1994-2020 Lua.org, PUC-Rio
make[1]: Leaving directory `/home/zhu_shiyong1/lua-5.4.0/src'

此时src目录下有lua可执行文件“lua”和lua静态文件“liblua.a”生成

make install可将生成的文件安装到指定的目录

打开Makefile文件,默认的安装路径如下:
INSTALL_TOP= /usr/local
为防止安装后覆盖之前所安装的版本(lua版本不一样),于是修改了安装路径如下:
#安装到用户目录下
INSTALL_TOP= ~/usr/local

执行make install

自此,lua的环境已经部署完毕,相关文件信息如下:

[zhu_shiyong1@hitry161 local]$ pwd
/home/zhu_shiyong1/usr/local
[zhu_shiyong1@hitry161 local]$ ls
bin  include  lib  man  share
生成bin  include  lib  man  share 5个文件夹

[zhu_shiyong1@hitry161 local]$ tree
.
├── bin
│   ├── lua
│   └── luac
├── include
│   ├── lauxlib.h
│   ├── luaconf.h
│   ├── lua.h
│   ├── lua.hpp
│   └── lualib.h
├── lib
│   ├── liblua.a
│   └── lua
│       └── 5.4
├── man
│   └── man1
│       ├── lua.1
│       └── luac.1
└── share
    └── lua
        └── 5.4

10 directories, 10 files
[zhu_shiyong1@hitry161 local]$ 

1.2、lua调用c函数

(1).c函数作为应用程序的一部分

代码如下:
代码出处:https://www.cnblogs.com/sifenkesi/p/3876745.html

#include <stdio.h>
#include <string.h>
//#include "lua.hpp"
#include <lauxlib.h>
#include <lualib.h>

//待Lua调用的C注册函数。
static int add2(lua_State* L)
{
        //检查栈中的参数是否合法,1表示Lua调用时的第一个参数(从左到右),依此类推。
        //如果Lua代码在调用时传递的参数不为number,该函数将报错并终止程序的执行。
        double op1 = luaL_checknumber(L,1);
        double op2 = luaL_checknumber(L,2);
        //将函数的结果压入栈中。如果有多个返回值,可以在这里多次压入栈中。
        lua_pushnumber(L,op1 + op2);
        //返回值用于提示该C函数的返回值数量,即压入栈中的返回值数量。
        return 1;
}

//另一个待Lua调用的C注册函数。
static int sub2(lua_State* L)
{
        double op1 = luaL_checknumber(L,1);
        double op2 = luaL_checknumber(L,2);
        lua_pushnumber(L,op1 - op2);
        return 1;
}

const char* testfunc = "print(add2(1.0,2.0)) print(sub2(20.1,19))";

int main()
{
        lua_State* L = luaL_newstate();
        luaL_openlibs(L);
        //将指定的函数注册为Lua的全局函数变量,其中第一个字符串参数为Lua代码
        //在调用C函数时使用的全局函数名,第二个参数为实际C函数的指针。
        lua_register(L, "add2", add2);
        lua_register(L, "sub2", sub2);
        //在注册完所有的C函数之后,即可在Lua的代码块中使用这些已经注册的C函数了。
        if (luaL_dostring(L,testfunc))
                printf("Failed to invoke.\n");
        lua_close(L);
        return 0;
}

编译运行:

[zhu_shiyong1@hitry161 ~]$ gcc lua_c.c  -I./usr/local/include/ -L./usr/local/lib/ -llua -o lua_c -ldl -lm
[zhu_shiyong1@hitry161 ~]$ ./lua_c 
3.0
1.1

(2).c函数库成为lua的模板

说到底就是编写lua可以require的库文件

lua_cso.c文件如下:
代码出处:https://www.cnblogs.com/sifenkesi/p/3876745.html

#include <stdio.h>
#include <string.h>
//#include <lua.hpp>
#include <lauxlib.h>
#include <lualib.h>

//待注册的C函数,该函数的声明形式在上面的例子中已经给出。
//需要说明的是,该函数必须以C的形式被导出,因此extern "C"是必须的。
//函数代码和上例相同,这里不再赘述。
static int add(lua_State* L)
{
        double op1 = luaL_checknumber(L,1);
        double op2 = luaL_checknumber(L,2);
        lua_pushnumber(L,op1 + op2);
        return 1;
}

static int sub(lua_State* L)
{
        double op1 = luaL_checknumber(L,1);
        double op2 = luaL_checknumber(L,2);
        lua_pushnumber(L,op1 - op2);
        return 1;
}

//luaL_Reg结构体的第一个字段为字符串,在注册时用于通知Lua该函数的名字。
//第一个字段为C函数指针。
//结构体数组中的最后一个元素的两个字段均为NULL,用于提示Lua注册函数已经到达数组的末尾。
static luaL_Reg mylibs[] = {
        {"add", add},
        {"sub", sub},
        {NULL, NULL}
};

//该C库的唯一入口函数。其函数签名等同于上面的注册函数。见如下几点说明:
//1. 我们可以将该函数简单的理解为模块的工厂函数。
//2. 其函数名必须为luaopen_xxx,其中xxx表示library名称。Lua代码require "xxx"需要与之对应。
//3. 在luaL_register的调用中,其第一个字符串参数为模块名"xxx",第二个参数为待注册函数的数组。
//4. 需要强调的是,所有需要用到"xxx"的代码,不论C还是Lua,都必须保持一致,这是Lua的约定,
//   否则将无法调用。
//extern "C" __declspec(dllexport)
int luaopen_mylib(lua_State* L)
{
        //const char* libName = "mytestlib";
        luaL_newlib(L,mylibs);
		//lual_register(L,mylibs);
        return 1;
}
[zhu_shiyong1@hitry161 ~]$ gcc lua_cso.c -shared -fPIC  -I./usr/local/include/ -L./usr/local/lib -llua -o mylib.so 

本以为上述命令可以直接生成mylib.so,无奈编译报错,指出编译liblua.a时没有加上-fPIC参数

/usr/bin/ld: ./usr/local/lib/liblua.a(lapi.o): relocation R_X86_64_32 against `.rodata.str1.1' can not be used when making a shared object; recompile with -fPIC

好吧,重新编译lua源码
注意:需修改lua的Makefile文件,在src/Makefile里面
找到这行代码
CFLAGS= -O2 -Wall -DLUA_COMPAT_ALL $(SYSCFLAGS) $(MYCFLAGS)
修改为
CFLAGS= -O2 -Wall -DLUA_COMPAT_ALL $(SYSCFLAGS) $(MYCFLAGS) -fPIC #后面加的-fPIC表示要编译位置无关代码
感谢下面小伙伴的帮助
https://www.jianshu.com/p/91fac87bd6d3

最后编译出了带有-fPIC的liblua.a的版本,并cp到/usr/local/lib里

再重新编译

[zhu_shiyong1@hitry161 ~]$ gcc lua_cso.c -shared -fPIC  -I./usr/local/include/ -L./usr/local/lib -llua -o mylib.so 

此时mylib.so库生成

[zhu_shiyong1@hitry161 ~]$ ll mylib.so 
-rwxr-xr-x 1 zhu_shiyong1 hitry 186704 Sep  2 14:18 mylib.so

试试效果如何:

[zhu_shiyong1@hitry161 ~]$ ./usr/local/bin/lua
Lua 5.4.0  Copyright (C) 1994-2020 Lua.org, PUC-Rio
> lib = require"mylib"
> print(lib.add(1,2))
3.0
> 

ok,大功告成!此时c库已成为lua的模板库。

1.3、c调用lua

代码出处:https://www.cnblogs.com/coderkian/p/4057750.html
test.c代码如下:

#include <stdio.h>
#include <lua.h>
#include <lualib.h>
#include <lauxlib.h>
#include <math.h>

int main() {
  lua_State *L = luaL_newstate();
  luaL_openlibs(L);

  if(luaL_loadfile(L, "test.lua") || lua_pcall(L, 0,0,0)){
    printf("error %s\n", lua_tostring(L,-1));
    return -1;
  }
  lua_getglobal(L,"add");
  lua_pushnumber(L, 10);
  lua_pushnumber(L, 20);
  if(lua_pcall(L, 2, 1, 0) != 0){
    printf("error %s\n", lua_tostring(L,-1));
    return -1;
  }
  int z = lua_tonumber(L, -1);
  printf("z = %d \n", z);
  lua_pop(L, 1);
  lua_close(L);
  return 0;
}

说明:
1.luaL_newstate创建一个新的lua_State,C和lua的所有操作都要依赖这个lua环境, luaL_openlibs将lualib.h中定义的lua标准库加载到进lua_State。
2.luaL_loadfile从文件中加载lua代码并编译,编译成功后的程序块被压入栈中,
3.lua_pcall会将程序块弹出并在保护模式下解释执行。代码中调用lua_pcall就在lua_State中定义了 width和 length两个全局变量。
4.lua_getglobal将全局变量的值压入栈中,width先入栈,在-2的位置,length在栈顶。

test.lua代码如下:

function add(x,y)
    return x+y
end

效果如下:

[zhu_shiyong1@hitry161 ~]$ gcc test.c -I./usr/local/include/ -L./usr/local/lib -llua -o test -lm -ldl
[zhu_shiyong1@hitry161 ~]$ ./test 
z = 30 

1.4、lua协程

coroutine:协同程序
摘自:https://www.runoob.com/lua/lua-coroutine.html
coroutine.create() 创建 coroutine,返回 coroutine, 参数是一个函数,当和 resume 配合使用的时候就唤醒函数调用
coroutine.resume() 重启 coroutine,和 create 配合使用
coroutine.yield() 挂起 coroutine,将 coroutine 设置为挂起状态,这个和 resume 配合使用能有很多有用的效果
coroutine.status() 查看 coroutine 的状态
注:coroutine 的状态有三种:dead,suspended,running,具体什么时候有这样的状态请参考下面的程序
coroutine.wrap() 创建 coroutine,返回一个函数,一旦你调用这个函数,就进入 coroutine,和 create 功能重复
coroutine.running() 返回正在跑的 coroutine,一个 coroutine 就是一个线程,当使用running的时候,就是返回一个 corouting 的线程号

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值