[Date Prev][Date Next][Thread Prev][Thread Next]
[Date Index]
[Thread Index]
- Subject: Re: Lua Multistate
- From: itbowman@...
- Date: Fri, 21 Jul 2000 15:38:43 -0000
--- In lua-l@egroups.com, "Russell Y. Webb" <rw20@c...> wrote:
> Here's what you can do. Install all your tags, files, and objects
through
> wrapper functions that record what is being installed as strings or
> filenames then the original thread can spawn another and pass it a
string
> or filename to initialize itself. Putting all the initialization
into one
> file and just telling the new thread (state) to call dofile on it
would
> seem to be cleanest.
>
> Just a quick idea which is likely to have some flaws.
>
> Russ
I have been using an approach much like the one Russ suggested
to support calling thread functions. I require that the module
starting a thread contain a global variable 'main' with value
function. I modified lua.c to stash the name of the file it
executes, and to call the main() function if it exists.
When the user starts a thread with 'call_thread( func, arg_tbl )',
I call lua_dofile() on the stashed filename to set up all
of the global state, and then I invoke the function stored in
global variable 'func'.
An example: file thread.lua [[
gbl = thread_global();
function foo( args )
for i = 1,50 do
print( args.text, gbl.n );
gbl.n = gbl.n + 1;
end
end
function main( args )
thread_call( foo, { text="hello" } );
thread_call( foo, { text="goodbye" } );
end
]]
This sets up shared-nothing states. I use two mechanisms to share
data between states (both based on C transfer).
1. I copy the 'args' table into the new state, and
pass it to the called function.
2. I implemented a userdata that has gettable and settable
tag methods; these look up the field in a hash table.
To create the userdata, the app calls
thread_global( name ). The name (default nil) indicates which
global table the threads would like to share. The global
tables can only store strings and numbers. I think it can
be extended easily to user data (provided the tags are created
in all threads by global initialization). Storing user data
would let you store other globals, which gives you something
like global table semantics (just slightly harder to set up;
maybe there's a nice way to do it though...haven't thought about
it much).
I thought that this approach would be pretty cheesy, but it
seems fairly robust (at least for the way I use lua).
It gives clean, shared-nothing semantics by default, but
lets threads share common data explicitly. It would be fairly
easy to break if a lua app changes the values of global
variables containing function values. By the way, I control
access to 'dangerous' builtins (such as print)
by replacing them with functions that grab a mutex then
call the original.
The main reason for choosing this approach is that I didn't need
to hit any of the lua source code (except for adding some
hooks to lua.c to store file name before doing a file).
I think this is important since 4.0 is only in Alpha right now.
The idea of copying tag methods and values to the new state
did occur to me, but I decided it is better to stick with
requiring the lua file to do all that setup statically, and
then do it once in each thread. I still need to extend
my approach to allow threads to be initiated from a lua_dobuffer()
call; unfortunately, I think I'll need to modify the lua
source slightly to do this (unless hooks for lua_dofile,
lua_dostring and lua_douffer are added to the main distribution).
Overall, I'm very happy with lua; it lets me write simple,
multi-threaded programs safely. If I spend enough thought
implementing the C code, I don't need to worry very much
about concurrency in the lua code. To me, that's marvellous.
Regards,
- Ivan Bowman
http://plg.uwaterloo.ca/~itbowman