弱表和GC终结使用C API [英] Weak table and GC finalizer using C API

查看:182
本文介绍了弱表和GC终结使用C API的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我试图通过使用C API将其存储在一个弱表中创建一个函数值的GC终结。

I am attempting to create a GC finalizer for a function value by storing it in a weak table using the C API.

我开始写在纯Lua的5.2原型:

I started off by writing a prototype in pure Lua 5.2:

local function myfinalizer()
   print 'Called finalizer'
end

function myfunc()
   print 'Called myfunc'
end

local sentinels = setmetatable({}, { __mode='k' })
sentinels[myfunc] = setmetatable({}, { __gc=myfinalizer })

myfunc()
myfunc = nil
collectgarbage 'collect'

print 'Closing Lua'

结果输出:

Called myfunc
Called finalizer
Closing Lua


原型似乎意欲工作。下面是C版:


The prototype seems to be working as intended. Below is the C version:

#include <stdlib.h>
#include <stdio.h>
#include "lua.h"
#include "lualib.h"
#include "lauxlib.h"

static int my_finalizer(lua_State *L)
{
    puts("Called finalizer");
    return 0;
}

static int my_func(lua_State *L)
{
    puts("Called myfunc");
    return 0;
}

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

    // create sentinels table (weak keys) in registry
    lua_newtable(L);                                    // t
    lua_newtable(L);                                    // t mt
    lua_pushstring(L, "k");                             // t mt v
    lua_setfield(L, -2, "__mode");                      // t mt
    lua_setmetatable(L, -2);                            // t
    lua_setfield(L, LUA_REGISTRYINDEX, "sentinels");    //

    // push global function and register as sentinel
    lua_pushcfunction(L, my_func);                      // f
    lua_getfield(L, LUA_REGISTRYINDEX, "sentinels");    // f t
    lua_pushvalue(L, 1);                                // f t k
    lua_newuserdata(L, 0);                              // f t k v
    lua_newtable(L);                                    // f t k v mt
    lua_pushcfunction(L, my_finalizer);                 // f t k v mt v
    lua_setfield(L, -2, "__gc");                        // f t k v mt
    lua_setmetatable(L, -2);                            // f t k v
    lua_settable(L, -3);                                // f t
    lua_pop(L, 1);                                      // f
    lua_setglobal(L, "myfunc");                         //

    // execute test script and exit
    if (luaL_dostring(L, "myfunc(); myfunc=nil; collectgarbage'collect'")) {
        printf("Error: %s\n", lua_tostring(L, -1));
    }
    lua_gc(L, LUA_GCCOLLECT, 0);    // suggestion: two full gc cycles
    fflush(stdout);                 // suggestion: immediate flush
    puts("Closing Lua");
    lua_close(L);

    fflush(stdout);
    return EXIT_SUCCESS;
}

使用编译:

$ gcc -std=c99 -Wall -Werror -pedantic -O2 -o main main.c -ldl -llua52 -lm

结果输出:

Called myfunc
Closing Lua
Called finalizer

C版有一些细微差别:

The C version has a few minor differences:


  1. 而不是我在注册表中存储的本地哨兵表。

  2. 使用零大小的用户数据,而不是与标记值__ GC 元方法的表。

  1. Instead of a local sentinels table I am storing in the registry.
  2. Using a zero sized userdata instead of a table for sentinel value with __gc metamethod.

我很困惑,为什么在C版本的 MYFUNC 终结不会运行完整的回收周期之后执行。我在做什么错了?

I am confused as to why in the C version the myfunc finalizer doesn't execute after running a full collection cycle. What am I doing wrong?

推荐答案

随着Lua的手动状态

只有具有明确的建设目标是从弱表中删除。值,如数字和淡C的功能,不受到垃圾收集,并因此不从弱表中删除(除非其相关联的值被收集)。

Only objects that have an explicit construction are removed from weak tables. Values, such as numbers and light C functions, are not subject to garbage collection, and therefore are not removed from weak tables (unless its associated value is collected).

my_func,并将无任何upvalues​​推,所以它是一种轻型的C函数,和垃圾收集过程中它不会从弱表中删除,因此相关的用户数据不不能成为垃圾关闭Lua的状态之前。您code应该工作,如果你使用Lua的函数,而不是 my_func,并将,或者如果你把 my_func,并将与upvalues (如果你确定的参数的顺序 lua_gc 来电!)。

Your my_func is pushed without any upvalues, so it is a light C function, and it isn't removed from weak tables during garbage collection, so the associated userdata does not become garbage before you close the Lua state. Your code should work if you use a Lua function instead of my_func, or if you push my_func with upvalues (and if you fix the order of the arguments in the lua_gc call!).

要总结,下面的值类型的的由弱表中删除(因为它们相关的键/值不会被删除):

To summarize, the following value types are not removed from weak tables (given that their associated keys/values aren't removed either):


  • 布尔值

  • 数字

  • 字符串

  • 光用户数据

  • 光C函数(LUA 5.2只)

其结果是你的程序应该可以正常工作和Lua 5.1,因为没有光的C函数(你仍然有修复 lua_gc 调用)。

As a consequence your program should work fine with Lua 5.1 because there are no light C functions (you still have to fix the lua_gc call).

这篇关于弱表和GC终结使用C API的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆