[Date Prev][Date Next][Thread Prev][Thread Next]
- Subject: RE: coroutines
- From: "Thiago Bastos" <hellraider@...>
- Date: Mon, 22 Nov 2004 18:37:38 -0300
Since no one seems to be contributing to this thread, I guess I'll just post
some hints. I don't have time to write a detailed explanation right now, but
maybe it's not even necessary (the theory is quite simple).
> When I first started using Lua, I had the same problem, I'm still not
> entirely sure how to set up something like that with coroutines. What
> I have ended up doing was setting up an event based processing system
> for lua objects and players. Basically each ai frame I loop through
> the players and handle any events they have pending, then I loop
> through non-player entities and handle their events. If I want
> something to happen in the future I just put the event in a queue
> (table) with a timer that gets counted down. When it reaches 0, I
> process and dump it.
I guess most people do that. It allows you to use only one Lua thread, but
adds a lot of complexity to the code.
The other approach is to have each agent running in a separate Lua Thread
(Lua Manual section 3.20). You must setup a Lua Thread for each "script
process". Then, you will want a scheduling mechanism where you have only ONE
of those threads executing at a time, so you get Lua multithreading in a
single OS thread.
Basically there are two "good" scheduling mechanisms for you:
Preemptive: you would use a hook (Lua Manual section 4.3) to limit the
processing done by each Lua thread. Harder to implement, higher overhead,
Implicit Cooperative: each thread does not have a well defined "time slice",
but will pass away control to another thread as soon as it does a "blocking
operation" (e.g. a call to Wait()). This is much easier to implement and is
potentially faster, the only drawback is that you must guarantee that all
scripts call blocking operations regularly. From experience, 99% of the
scripts will have these calls naturally. Those that must execute (nearly)
100% of the time can call a special function: pass() or something like that
to pass away control to another thread.
Now, to implement implicit cooperative scheduling: you need a real scheduler
with a "ready" process queue and a "blocked" process queue, etc. Keeping
track of the process states is up to you.
Whenever you must run a script (inside your scheduler), use lua_resume().
Whenever you must block the current script, use lua_yield(). That's inside
all your "blocking" C functions exported to Lua (e.g. Wait()). When you call
lua_yield(), the lua_resume() call from within your scheduler will return.
There you will check if the script simply "finished", or if it was really
blocked. Then you'll simply schedule another script (lua_resume() again).
As soon as an IO/blocking operation is completed, you return the "blocked"
script to the "ready" process queue.
You can use lua_resume() to feed parameters to the script (e.g. a
WaitForMessage() function could return a message when it "resumes").
That's it, I guess... hope that helps.
Btw, I was writing a "toolkit" for developing Lua agents for games which
would feature C++/Lua auto-binding and multithreading management, but had to
stop working on it to work on other things.