Lua的setfenv函数在线程上似乎不起作用。

我想在lua状态下_load_一些函数,然后能够从_lua线程_调用函数。 我正在尝试对线程进行setfenv操作,以便它们创建的变量_限于线程_而不出现在全局环境中。

Am I doing anything wrong here ? (我不想在线程上加载函数,因为可能有很多个线程,将它们一次加载到状态似乎是正确的方法)

--编辑--

解决方案似乎是:

为每个线程创建一个新的env表(带有__index = _G) 对于在其中运行的每个函数,执行setfenv(f1,getfenv(0))

点赞
用户12048
用户12048

每个函数都有自己的 fenv。f1的 fenv 是 _G,所以无论在哪个线程中调用它,它都会在 _G 中设置全局变量。

一种选项是在 f1 中显式引用线程环境,例如:

function f1()
  local env = getfenv(0)
  env.my_var = 100
  print('var set')
end

另一种选项是为每个线程提供一个 f1 的私有副本。

第三种选项是创建一个代理 fenv(对于所有线程和函数都是相同的),具有 __index__newindex 元方法,它们委托给当前线程环境(即 getfenv(0)):

-- 步骤1:创建共享代理对象,委托给当前线程环境。
local tlproxy = {} -- 总是为空
local tlproxy_mt = {}

function tlproxy_mt:__index(k)
  return getfenv(0)[k]
end

function tlproxy_mt:__newindex(k, v)
  getfenv(0)[k] = v
end

setmetatable(tlproxy, tlproxy_mt)

-- 步骤2:为每个新线程创建一个新的空环境表。
local tenv_mt = {}
tenv_mt.__index = _G -- 允许访问_G.math等。

local function createThread(f)
  local thread = coroutine.create(f)
  -- 如果从新线程中调用这些函数,它们将不能正常工作,因此需要禁用它们。
  local tenv = {
    load=false, loadfile=false, loadstring=false,
    module=false, require=false
  }
  setmetatable(tenv, tenv_mt)
  debug.setfenv(thread, tenv)
  return thread
end

-- 步骤3:当一个函数应该使用线程局部变量时,应将“tlproxy”作为它的fenv。
function f1()
  my_var = 0
  while true do
    my_var = my_var + 1
    coroutine.yield(my_var)
  end
end
setfenv(f1, tlproxy)

local c1 = createThread(f1)
local c2 = createThread(f1)

-- 输出应为1、1、2、2...
-- 如果没有线程局部变量,它将为1、2、3、4...
for _ = 1, 100 do
  print(coroutine.resume(c1))
  print(coroutine.resume(c2))
end
2013-07-10 09:31:40