This is a read-only snapshot of the ComputerCraft forums, taken in April 2020.
Molinko's profile picture

coroutine management

Started by Molinko, 07 February 2014 - 08:12 PM
Molinko #1
Posted 07 February 2014 - 09:12 PM
Q:) I was wondering if someone could clarify some points to me about coroutines and a management system for them. I've looked in to the parallel api to see how 'runUntilLimt' works and thats pretty clear to me but I was wondering if there's a more dynamic approach to running tasks or coroutines.
I've also looked into goroutine although some of that is a little above my head..

How can I manage a system where one coroutine or task can spawn new subroutines?
And further, would it be pointless to have a system where routines run and monitor themselves until they're finished and push themself off of the running coroutine stack / listOfActiveRoutines??

Let me know if im being too ambiguous or unclear.. Thanks in advance for any help
LBPHacker #2
Posted 08 February 2014 - 03:37 AM
How can I manage a system where one coroutine or task can spawn new subroutines?
Managing coroutines is all about keeping them alive and not resuming them after they die. If you have a list of them, you can just provide a function in the global environment that adds coroutines to that list:
local crList = {}

function coroutine.start(func, ...) -- call this whatever you want
  if type(func) ~= "function" then return false end
  local cr = coroutine.create(func)
  coroutine.resume(cr, ...) -- comment this if your coroutines yield at the end of their endless loops
  crList[cr] = true -- yay, you can even store useful information here about the coroutine
end

coroutine.start(loadfile("rom/programs/shell"))

while true do
  local eventData = {coroutine.yield()}
  for key in pairs(crList) do
    coroutine.resume(key, unpack(eventData))
  end
  if coroutine.status(key) == "dead" then crList[key] = nil end
end

As for the second question; coroutines can't check themselves if they are dead, because if a coroutine is checking itself, that means it is very much alive. You could of course put a wrapper around the function passed to coroutine.start that removes the coroutine from the list, but it's pointless. There will always be an endless loop that manages the coroutines, and the lower part of that loop is a good place to check for dead coroutines.
Edited on 08 February 2014 - 02:37 AM
surferpup #3
Posted 11 February 2014 - 02:48 PM
Check out this thread. [member='theoriginalbit'] has a coroutine management system that you can look at posted in there on pastebin, and there is discussion of it in answer to several of my questions.
Molinko #4
Posted 11 February 2014 - 03:09 PM
Check out this thread. [member='theoriginalbit'] has a coroutine management system that you can look at posted in there on pastebin, and there is discussion of it in answer to several of my questions.

Ah yeah thanks for that. I have already. Its a nice example of a scheduler. I've been mucking about with a few variations of my own but I'm still a bit cloudy on what is really necessary. Let me know if you want to toss some ideas around eh? Little code collaboration for knowledge :)/>
surferpup #5
Posted 11 February 2014 - 06:37 PM
Ah yeah thanks for that. I have already. Its a nice example of a scheduler. I've been mucking about with a few variations of my own but I'm still a bit cloudy on what is really necessary. Let me know if you want to toss some ideas around eh? Little code collaboration for knowledge :)/>

The reason I mentioned the thread is that [member='theoriginalbit'] answers my questions about it in there. It is a pretty decent starting location.

For example, I learned that coroutine.yield() and os.pullEventRaw() are for all intents and purposes identical.

The basics of coroutines are pretty straight forward. Here is some testing code I wrote while just playing around with this:



-- Some  function declarations
local function myFunction (someVariable)
  someVariable = someVariable or "NIL"
  print("In My Function: "..someVariable)
  local event = {os.pullEvent("key")}
  print("In Function: event=",unpack(event))
  return "...Done..."
end

local myOtherFunction = function()  
  print("In My Other Function")
end

-- create a coroutine (does not start it)

print (type(myFunction)) --"function"
local myFirstCoRoutine = coroutine.create(myFunction)
print(type(myFirstCoRoutine)) --"thread"
print(coroutine.status(myFirstCoRoutine)) --"suspended"

-- start the coroutine
print ("Function resume return values, initial call = ",coroutine.resume(myFirstCoRoutine,"Hello",...) )-- can pass in arguments
-- will print "truekey" here because function is waiting for a key event.
print(coroutine.status(myFirstCoRoutine)) --"suspended"

repeat 
  local event = { coroutine.yield() }
  print("In Main Event=",unpack(event))
  if event[1]=="key" then -- gonna have to check here or in the thread function
    print ("Function resume return values = ",coroutine.resume(myFirstCoRoutine,unpack(event)))
  end
until coroutine.status(myFirstCoRoutine) == "dead"

print(coroutine.status(myFirstCoRoutine)) --"dead"