You asked for - Coroutines

Simple rule, I ask, you request, I comply. No ask, no get... A user (Anonymously) asked if I could post an article on Coroutines and explain how it could be used, so here it is.

Disclaimer : I am not an expert in Lua myself and there are a lot of aspects that I need to familiarise myself with.

Now that we have that out of the way, Here's my understanding of co-routines and how they could be used.

What is a co-routine

A co-routine is a thread but I found it to be different from being a thread. When you call a function, the return address is pushed to the stack, so that when the function is over the processing can return to where it branched off from. A co-routine is more like a function that can be interrupted and resumed. A co-routine is a way to split the execution of a function until a point and can then resume execution from that point onwards. Lua co-routines are not multi-threaded in the way threads are on PC/Mac, they are collaborative multi-tasking.

What are the co-routine functions

The functions associated with co-routines are
coroutine.create - Creates a new coroutine thread
coroutine.resume - Start or resume a thread
coroutine.running - Returns the running coroutine
coroutine.status - Returns the status of a thread
coroutine.wrap - Creates a thread and returns a function to resume it
coroutine.yield - Yields execution of thread back to the caller 

How to use co-routines

Step 1. Create a new co-routine

local function f(a,b)
  print(a,b)
end

thread = coroutine.create (f)  -- thread will run function f

Step 2. Return execution to the main thread

local function f(a)
  print("I have started this function with the value " .. a)
  v = coroutines.yield("Bummer")
  print("The value of v is now " .. v)
  return 2011
end

thread = coroutines.create(f)

_,result = coroutine.resume(thread,1900) -- This shall run the thread/start it up
print(result)  -- See what we got from yield

_,result = coroutines.resume(thread,2000)
print(result) -- See what the function returned


When a coroutines is called using yield(params), the arguments passed in yield are returned to the caller/main thread
When a coroutine is resumed using resume(thread, params) the parameters are passed as if they were passed to the function

Sometimes, in a context that I cannot put to words, you might have a co-routine running that might do several things and keep on being resumed/paused, etc you would want to know if the co-routines is running or suspended or dead, (let's say if you were responding to a event).

so status = coroutine.status(thread) will return one of the four states

running
normal
suspended
dead

so before you resume, you can check if it is suspended, only then resume it.

Closing words

I am still trying to work out how they can be useful, In some cases where you want to do a complex long processing, one can have a series of yields and resumes in the function like
local function doLongProcessing(a)
  --Do processing 25%
 thread1 = coroutines.yield("25%") --> this can be used to update the screen somewhere
  --Do processing 50%
 thread1 = coroutines.yield("50%") --> this can be used to update the screen somewhere
  --Do processing 100%
 thread1 = coroutines.yield("100%") --> this can be used to update the screen somewhere
--All done
end

and of course you will also need to have in the main thread something like
 thread = coroutine.create(f)

while coroutine.status(thread) ~= "dead" do
 _,res = coroutine.resume(thread)
 --do something with the returned value
 print("Progress is " .. res)
end

I shall add more samples and explanation as I figure out the usage of this myself. I was looking for something that was equivalent of DoEvents() from VB6 something that is a breather for the loops/main thread. If you were to run this code
local text = display.newText("",10,100,nil,14)

 for i=1,10000 do
  -- do nothing
  text.text = i
end

you will find that the app gets blocked, on the simulator you see the wait animation (BeachBall), and when it responds, the text will display 10000, what I was after was that it should display every number that I has iterated through. Now coroutines will also not help us there, the only way to do this is by using the onEnterFrame, so I am forced to think on what is the better and more optimal way to get things done.

If you have an feedback, please feel free to post comments, if you post them anonymously, that's fine too, but if you put your name, I can attribute you for the same.

Comments

  1. good tutorial
    how about math functions and calculations (and their practical usage)next time, please?

    ReplyDelete
  2. or maybe more about animations? sprites and movieclip

    ReplyDelete
  3. Here's a good example of how to use coroutines. A substitute for state machines: http://eli.thegreenplace.net/2009/08/29/co-routines-as-an-alternative-to-state-machines/

    ReplyDelete

Post a Comment

Popular Posts