Lua userdata资源释放

http://blog.csdn.net/doudouhuy/article/details/6214141

 首先来一段PIL中的说明:

Life is not always that easy. Sometimes, an object needs other resources besides raw memory, such as file descriptors, window handles, and the like. (Often these resources are just memory too, but managed by some other part of the system). In such cases, when the object becomes garbage and is collected, somehow those other resources must be released too. Several OO languages provide a specific mechanism (called finalizer or destructor) for that need. Lua provides finalizers in the form of the __gc metamethod. This metamethod only works for userdata values. When a userdatum is about to be collected and its metatable has a __gc field, Lua calls the value of this field (which should be a function), passing as an argument the userdatum itself. This function can then release any resource associated with that userdatum.

    假设现在我们需要写一个遍历目录的库,遍历文件基本流程是:

findFile   -> 打开一个编译句柄

nextFile  -> 遍历目录中的文件

closeFind -> 遍历完成

 

在lua使用遍历目录库:

for name in dir(path) do .... end

 


:dir是库中注册进去的API,支持for in 泛型语法。跟进Lua要求,需要dir返回一个迭代器(必须),可选的返回状态变量和控制变量。

如果for name in dir(path) do ... end 完全执行完毕,中间不会退出或者中断,那么不用考虑太多问题。但是如果中间会退出呢?比如说,编译某个目录,查找文件名为A的文件,如果找到了就退出。大致lua代码如下:

for name in dir(path) do

if (name == A) then

return

end

end

 

由于遍历需要通过findFile打开一个查询句柄,我们需要显示的释放此句柄。类似 查找进程、打开文件等等都是如此,分配的系统资源必须在不用的时候释放。

回到上面的问题,如何保证打开的查下句柄能正常释放呢?利用userdata的__gc metathod。 lua中的userdata在被回收的时候,会调用其__gc metathod方法。如是乎,我们只需要为__gc写一个metathod方法即可实现。

1、定义一个简单数据结构,用于遍历目录保存查询句柄和一些额外信息:

 

  1. struct dir_info  
  2. {  
  3.     intptr_t    m_Handle;  
  4.     bool        m_bClosed;  
  5.     char        m_pattern[MAX_FILE_PATH_LEN+1];  
  6. };  
 

 

2、定义我们的dir函数

[c-sharp] view plain copy print ?
  1. static int dir(lua_State *L)  
  2. {     
  3.     const char *path = luaL_checkstring(L, 1);  
  4.     if (!path) {  
  5.         cout << "need string type param for file path" << endl;  
  6.         return 0;  
  7.     }  
  8. #ifdef RETURN_ITERFUN_AND_STATUS  
  9.     lua_pushcfunction(L, dir_iter);  
  10. #endif  
  11.     dir_info *di = static_cast<dir_info *>(lua_newuserdata(L, sizeof(dir_info)));   
  12.     if (!di) {  
  13.         cout << "no memory" << endl;  
  14.         return 0;  
  15.     }  
  16.     di->m_Handle = 0;  
  17.     di->m_bClosed    = false;  
  18.     sprintf(di->m_pattern, "%s//*.*", path);  
  19.     luaL_getmetatable(L, DIR_METATABLE);  
  20.     lua_setmetatable(L, -2);  
  21. #ifdef RETURN_ITERFUN_AND_STATUS      
  22.     return 2;   
  23. #else  
  24.         lua_pushcclosure(L, dir_iter, 1); // 将当前堆栈定的UseData当做dir_iter的upvalue值  
  25.     return 1;  
  26. #endif    
  27. }  
 

 

3、定义真正的迭代函数dir_iter

[c-sharp]
view
plain
copy print ?
  1. static int dir_iter(lua_State *L)  
  2. {  
  3.     dir_info *di = 0;  
  4. #ifdef RETURN_ITERFUN_AND_STATUS  
  5.     di = (dir_info *)luaL_checkudata(L, 1, DIR_METATABLE);  
  6. #else     
  7.     di = (dir_info *)lua_touserdata(L, lua_upvalueindex(1));  
  8. #endif  
  9.       
  10.     if (!di){  
  11.         cout << "fatal error " << endl;  
  12.         lua_pushnil(L);  
  13.         lua_pushstring(L, "get upval failed");  
  14.         return 2;  
  15.     }  
  16.     _finddata_t fd;  
  17.     if (0 == di->m_Handle) {  
  18.         if (-1 == (di->m_Handle = _findfirst(di->m_pattern, &fd)))  
  19.         {  
  20.             cout << "find file failed errono=" << errno << endl;  
  21.             lua_pushnil(L);  
  22.             lua_pushstring(L, "find file failed");  
  23.             return 2;  
  24.         }  
  25.         else  
  26.         {  
  27.             cout << "find first file : " << fd.name << endl;  
  28.             lua_pushstring(L, fd.name);  
  29.             return 1;  
  30.         }         
  31.     }  
  32.     else  
  33.     {  
  34.         if (-1 == _findnext(di->m_Handle, &fd))  
  35.         {             
  36.             _findclose(di->m_Handle);  
  37.             cout << " end of find file..." << endl;  
  38.             di->m_bClosed = true;  
  39.             return 0;  
  40.         }  
  41.         else{  
  42.             cout << "find file : " << fd.name << endl;  
  43.             lua_pushstring(L, fd.name);  
  44.             return 1;  
  45.         }  
  46.     }     
  47. }  

4、
定义我们的清理函数

[c-sharp]
view
plain
copy print ?
  1. static int dir_clean(lua_State *L)  
  2. {  
  3.     dir_info *di = static_cast<dir_info *>(lua_touserdata(L, 1));  
  4.     if (!di){  
  5.         cout << "dir_clean failed , can't get dir_info " << endl;  
  6.         return 0;  
  7.     }  
  8.     else{  
  9.         if (!di->m_bClosed){  
  10.             cout << "------dir_clean------" << endl;  
  11.             _findclose(di->m_Handle);  
  12.             di->m_bClosed = true;  
  13.         }         
  14.     }  
  15.     return 0;  
  16. }  

5、
OK,现在可以注册dir了

[c-sharp]
view
plain
copy print ?
  1. static const luaL_reg dirLib[] = {  
  2.     {"dir", dir},  
  3. };  
  4. void luaopen_dir(lua_State *L)  
  5. {         
  6.     create_dir_metatable(L);          
  7.     luaL_register(L, "libdir", dirLib);  
  8. }  

6、
别忘了,还有create_dir_metatable,这个主要目的是增加__gc metatable

[c-sharp]
view
plain
copy print ?
  1. static int create_dir_metatable(lua_State *L)  
  2. {     
  3.     luaL_newmetatable(L, DIR_METATABLE);  
  4.     lua_pushstring(L, "__gc");  
  5.     lua_pushcfunction(L, dir_clean);  
  6.     lua_settable(L, -3);  
  7.     return 1;  
  8. }  

 


意,上面的宏定义使用了2中方法。


果定义了宏RETURN_ITERFUN_AND_STATUS,dir
返回迭代器dir_iter和状态变量;


果没有定义RETURN_ITERFUN_AND_STATUS宏,dir只返回迭代器函数,参数作为迭代器函数的upvalue携带过去。


种方式都能达到泛型遍历的效果。

 


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值