LUA中绑定C对象的3种方法
Posted bywayboy
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了LUA中绑定C对象的3种方法相关的知识,希望对你有一定的参考价值。
对于C 和LUA之间的对象绑定, 大致可以分为以下几种.
- 全集C对象指针.
- 生存周期完全由C控制的指针.
- 生存周期完全由LUA控制的指针.
针对以上3种场景, 我们可以用下面的方法进行对象绑定.
1. 在整个软件生存周期都有效的对象指针
这种类型的C对象, 不用关心C对象的生存周期. 可以使用 lua upvalue 来进行绑定.
static int lua_function_method1(lua_State * L)
you_c_ptr * obj = (you_c_ptr *)lua_touserdata(L, lua_upvalueindex(1)); //通过 upvalue 获取c对象
luaL_Reg lua_functions[] =
"method1", lua_function_method1,
NULL, NULL
;
int luaopen_cobject(lua_State * L)
## 直接返回一个方法表.即可
lua_newlibtable(L, lua_functions);
lua_pushlightuserdata(L, c_object_ptr);
luaL_setfuncs(L, lua_functions, 1);
return 1;
2. 不知道何时会失效的C对象.
这类对象的生存周期不确定, 比如一个网络连接, 在你的程序运行的任何时间它都有可能失效(比如:连接断开了). 可以给C对象增加一个引用计数, 同时使用匿名元表的方式来绑定到lua对象.
/*
绑定对象的工具函数
Lua 虚拟机指针, 方法表, 方法数目, upvalue数, __index 原方法(没有可以提供 NULL)
*/
int lua_bind_metatable(lua_State * L, int i, luaL_Reg * methods, int reg_sz, int nups, lua_CFunction _index)
int top = lua_gettop(L);
lua_createtable(L, 0, reg_sz);
top = lua_gettop(L);
lua_rotate(L, -(1 + nups), 1);
luaL_setfuncs(L, methods, nups);
top = lua_gettop(L);
lua_pushliteral(L, "__index");
if(_index)
lua_pushcfunction(L, _index);
else
lua_pushvalue(L, -2);
lua_rawset(L, -3);
lua_pushliteral(L, "__metatable");
lua_pushliteral(L, "not allow access metatable");
lua_rawset(L, -3);
top = lua_gettop(L);
printf("set metatable to type: stack:%d, type:%d\\n", i + nups - 1 , lua_type(L,i + nups - 1));
lua_setmetatable(L, i + nups -1);
top = lua_gettop(L);
return 0;
static int lua_function_method1(lua_State * L)
//通过 upvalue 获取c对象
you_c_ptr * obj = (you_c_ptr *)lua_touserdata(L, lua_upvalueindex(1));
// .... you code is here.
/*减少引用计数*/
void c_obj_release(you_c_ptr * ptr)
ptr->refCount--;
if(0 == ptr->refCount)
free(ptr);
void c_obj_add_ref(you_c_ptr * ptr)
ptr->refCount++;
static int lua_function___gc(lua_State * L)
// 通过 upvalue 获取c对象
you_c_ptr * obj = (you_c_ptr *)lua_touserdata(L, lua_upvalueindex(1));
// 其它释放资源的方法.
// ...
// 减少引用计数
c_obj_release(obj);
luaL_Reg lua_functions[] =
"method1", lua_function_method1,
"__gc", lua_function___gc,
NULL, NULL
;
/*获取 LUA 对象*/
int luaopen_cobject(lua_State * L)
## 由于需要用到gc原方法, 这里只能返回一个元表了.
## lua种所有 lightuserdata 是共用一个元表的, 用此 这里需要一个空table作为lua对象的this
lua_newtable(L, 0, 0);
lua_pushlightuserdata(L, you_c_obj_ptr);
c_obj_add_ref(you_c_obj_ptr);
lua_bind_metatable(L, lua_functions, sizeof(lua_functions[0]) / sizeof(lua_functions), 1, NULL);
return 1;
3. 生存周期都由LUA 控制的C对象
这类C对象 是通过 lua_newuserdata(sizeof(cobject_t)) 来创建的. 具有以下两种情形
- 有析构函数 则可以采用第2种方法来返回LUA对象. 不同的是它不需要引用计数.
- 无析构函数 则可以使用第1种方法来返回LUA对象.
通过以上方法得到的lua对象 在访问对象方法的时候都可以使用 “.” 而非 “:”. 原因是他们的this指针都在方法的 upvalue里面.
4. 涉及到协程调度.
LUA 的垃圾回收器并不会关心协程是否处于挂起状态还是dead状态, 只要没有变量引用到它, 则会对其进行回收.
好在 LUA_REGISTRYINDEX 是全局的, 我们可以再yeild之前 使用 lua_pushthread 将其压入堆栈然后用luaL_ref 引用到注册表中, 以确保当前线程不会被垃圾回收器强行回收掉.
因此, 当您再库中挂起一个协程并等待唤醒的时候, 需要对其进行引用.
以上是关于LUA中绑定C对象的3种方法的主要内容,如果未能解决你的问题,请参考以下文章