|
On Jan 29, 2005, at 18:41, André Carregal wrote:
PS I struggle with co-routines.Doesn't everyone? :o)
Well, here we go again, my first foolish attempt to make sense of this new Wonderland. I really do feel like Alice though. Or was it Dorothy? One way or another, we are not in Kansas anymore!
Anyhow, I tried to wrap this coroutine business with something more or less semantically equivalent to NSThread +detachNewThreadSelector:toTarget:withObject:
http://developer.apple.com/documentation/Cocoa/Reference/Foundation/ ObjC_classic/Classes/NSThread.html
It goes something like this: -- Assume some 'long' running object local aConvolutedObject = ConvolutedObject.new() -- The 'magic' incarnation local aTask = LUTask.new( aConvolutedObject, aConvolutedObject.doIt() ) -- Run the task aTask.run()A LUTask provides a couple of public methods to access the standard coroutine functionalities:
aTask.status() aTask.resume() aTask.yield()As well as accessor methods to what underlying LUObject and method the task is running:
-- returns the underlying object this task is wrapped around aTask.object() -- returns the underlying method that will be execute aTask.method() The 'magic' happens in the "run" method:-- instance method to 'run' the routine by registering it with the class run loop
local run = function() if not ivars.routine then routine() self.class().register( self ) end endFirst, the method check if it was run already or not. Then, if this is the first time, it register itself with the class run loop.
The private 'routine' method creates the 'coroutine' itself: -- private method to wrap ivars.method in a coroutine local routine = function() if not ivars.routine then ivars.routine = coroutine.create( self.method() ) end return ivars.routine end Then the task is passed on to LUTask.register(): -- class method to register a task with the run loop local register = function( aTask ) if aTask then aTask.object().setTask( aTask ) tasks().add( aTask ) run() end endLUTask.register() simply adds the given task to its list and set it as the current task of the underlying object:
aTask.object().setTask( aTask )This allows any LUObject to access their current 'task' when their coroutine method is invoked:
local doIt() -- do stuff this.task().yield() -- do some more stuff this.task().yield() -- be done with it end Finally, LUTask.register() kicks in the run loop itself: -- class method to 'run' through all the tasks local run = function() local someTasks = tasks() if someTasks then local count = someTasks.size() if count > 0 then for index = 1, count dolocal aTask = someTasks.get( index )
local aStatus = aTask.status() if aStatus == "dead" thenaTask.object().setTask( nil ) someTasks.remove( index )
else aTask.resume() end end end end endThe run loop goes through the list of tasks and check their status. If a task is 'dead' (ie finished), it removes it from its list. Otherwise, it invokes its resume() method.
The run loop runs only once through the list... this is somewhat on purpose... as I would like to avoid the run loop "busy waiting" on something to execute even when strictly nothing is going on at all... ideally I would like to have some sort of "event" driven system... but I have no idea how to do that yet... instead the run loop "rewind" itself by somehow (ab)using recursion... the "rewinding" is driven by the objects being executed... each time an object interacts with its task, the run loop gets automatically "rewinded":
-- instance method to yield the routine local yield = function() if ivars.routine then-- note the additional call to LUTask.run() at the end of the return statement
return coroutine.yield( self.routine() ), self.class().run() end return nil endNot sure if any of this will fly in practice as I even tested this concoction yet :))
See attachment for the current draft implementation. Feedbacks and head slapping very much welcome! Cheers -- PA, Onnay Equitursay http://alt.textdrive.com/
Attachment:
LUObject.lua
Description: Binary data
Attachment:
LUTask.lua
Description: Binary data
Attachment:
LUList.lua
Description: Binary data