lua-users home
lua-l archive

[Date Prev][Date Next][Thread Prev][Thread Next] [Date Index] [Thread Index]



However, I think wrapping your scripts should work:
return function(...)
-- original script goes here
end

Then, you can lua_load the script once and lua_call it each time you want a fresh function instance. That'll be dead fast.

[snip snip]

But that only works for a single level. Any functions _called_ by that
closure are still bound to the original environment. In this case,
calling "bar" puts you right back where you started.

Attached is another approach. Give it a spin and then try to unravel what's happening! :-)

--
Wim



--
-- thread local globals ?!?
--

local getfenv = getfenv

-- get thread local global
local function getglobal(self, index)
	return getfenv(0)[index]
end

-- set thread local global
local function setglobal(self, index, value)
	getfenv(0)[index] = value
end

-- reroute fun to thread local globals
function tlg(fun)
	setfenv(fun, setmetatable({}, {
		__index = getglobal,
		__newindex = setglobal,
	}))
end

-- helper to prepare a coroutine with a separate environment
-- (cannot be done from Lua otherwise.)
function start(fun, name)
	return coroutine.create(function()
		-- set some thread local globals
		setfenv(0, setmetatable({
			name = name,
			j = 1,
		}, { __index = _G}))

		-- start fun
		fun()
	end)
end


-- OK, let's give it a spin
-- here's some innocent volunteer...
-- note that it exclusively uses globals.
function count()
	for i = 1, 4 do
		print("in thread " .. name .. ", j = " .. j)
		j = j + 1
		coroutine.yield()
	end
	print("thread " .. name .. " is done!")
end

-- reroute to thread local globals
tlg(count)


-- prepare two threads to run function count.
t1 = start(count, "t1")
t2 = start(count, "t2")

-- execute in some random order and see what happens...
coroutine.resume(t1)
coroutine.resume(t1)
coroutine.resume(t1)
coroutine.resume(t2)
coroutine.resume(t1)
coroutine.resume(t2)
coroutine.resume(t1)
coroutine.resume(t2)
coroutine.resume(t2)
coroutine.resume(t2)