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

Coroutine manager

Started by Creeper9207, 01 September 2015 - 09:13 PM
Creeper9207 #1
Posted 01 September 2015 - 11:13 PM
Can someone link me to (or make) a simple Couroutine manager? I can't figure out coroutines for the life of meh :P/>
KingofGamesYami #2
Posted 01 September 2015 - 11:24 PM
Step 1: Make the parallel API (Literally study it until you know what everything does)

Step 2: Make the Multishell API (Study this until you know what everything does - and why)

Step 3: Customize.
Creeper9207 #3
Posted 02 September 2015 - 12:05 AM
My problem:
I can't figure out how to pause a coroutine, and I can't figure out how to 'dedicate' a window to a coroutine per say, but I hear it can be done
KingofGamesYami #4
Posted 02 September 2015 - 12:20 AM
The correct way to pause a coroutine would be to stop resuming it with events related to user input. Other events are important: If the coroutine calls sleep and never receives the "timer" event, it will be "broken", and continue to yield forever.

You can dedicate a window to a coroutine the same way the window API does it. Basically just term.redirect() to that window before resuming said coroutine.
Creeper9207 #5
Posted 02 September 2015 - 12:32 AM
ok, I think I understand most of it, but one thing, how can i run a file in a couroutine? when I do pausing the couroutine doesnt work
HPWebcamAble #6
Posted 02 September 2015 - 12:46 AM
When you call 'coroutine.yeild' in a function, that's basically saying to the function's 'parent' (The thing that ran the function, usually a coroutine manager) "I've done what I need to, tell me if anything happens I need to know about"

os.pullEvent() pretty much just calls coroutine.yeild, and it isn't from Lua, its a CC function.
You can also pass an argument to coroutine.yeild - This is usually interpreted as the 'filter' - What the coroutine wants, or the event its looking for.

So a coroutine's job is to yeild when its done, and is waiting for something to happen.
A coroutine manager needs to pass the appropriate events to the correct coroutine, such as input events to the coroutine 'in focus' (And should respect the 'filter' from a coroutine)

The coroutine manager keeps calling coroutine.resume on its coroutines, passing event data as arguements, until all coroutines have ended ( 'coroutine.status( coroutineName )' will return "dead", meaning the function returned, or finished )


Here's a great example/tutorial:
http://www.lua.org/pil/9.1.html


Someone please correct me if I got anything wrong :)/> , I've never actually used coroutines myself
KingofGamesYami #7
Posted 02 September 2015 - 12:53 AM
ok, I think I understand most of it, but one thing, how can i run a file in a couroutine?

Make the file into a function. Check out loadfile :)/>
Creeper9207 #8
Posted 02 September 2015 - 01:07 AM
er, but then how would I pause it if the function never stops?
HPWebcamAble #9
Posted 02 September 2015 - 01:19 AM
er, but then how would I pause it if the function never stops?

You cannot. A function must call coroutine.yeild at some point, otherwise it will be stopped by CC after 10 or 15 seconds for hogging the Lua VM
(There isn't a true multitasking system in Lua, only one function may run at a time. Yes, this includes all computers on the server)
Edited on 01 September 2015 - 11:19 PM
Creeper9207 #10
Posted 02 September 2015 - 03:17 AM
function ()
shell.run()
coroutine.yield()
end
^How do i make it pause before the file ends

And you can have a function that never ends
while true do
sleep(1)
end
HPWebcamAble #11
Posted 02 September 2015 - 03:34 AM
function ()
shell.run()
coroutine.yield()
end
^How do i make it pause before the file ends

In this function, this is how it would go down:
  1. Coroutine manager starts the function
  2. shell.run() returns false
  3. the function returns control to the coroutine manager (when it calls 'coroutine.yeild()')
  4. In general, the coroutine manager yeilds as well, until an event is triggered (say, a 'mouse_click')
  5. If there are no other coroutines to worry about, the manager simply passes the event 'mouse_click' (and its arguments)
  6. Since the function doesn't assign the result to a variable, it simply ends, returning control to the manager (and its state becomes 'dead')
  7. The manager discards the function, as it is now finished

And you can have a function that never ends
while true do
sleep(1)
end
  1. Coroutine manager starts the function
  2. Calls 'sleep(1)' which starts a timer and then returns control to the coroutine manager
  3. The coroutine manager waits for an event. If its a timer, it is passed to the function.
  4. The while loop begins again - sleep(1) is called
  5. From 2
So no, this wouldn't end, unless the coroutine manager decieded to stop resuming the function
For example, if the coroutine manager was part of an OS, the user might close the program. The coroutine manager discards the function, therefore no longer resuming it.

Usually, the coroutine manager is the Parallel API, I believe it is called when the computer starts and runs rednet and the shell API or something like that.
Creeper9207 #12
Posted 02 September 2015 - 03:52 AM
well, how would i bypass this? i need a way to pause programs with a basic coroutine manager :L

Reason i'm so buggy about it, I don't want to release my os without multitasking in it
Bomb Bloke #13
Posted 02 September 2015 - 04:02 AM
If it helps, here's an example of a coroutine manager, one with enough comments in it that you should be able to see exactly how it operates.

Normally, you resume your coroutine as soon as you have an event of the sort it requested when it yielded. Pausing an arbitrary bit of code for an arbitrary amount of time adds an extra condition: you have to get the right event, and you need to wait for your "unpause" condition.

But multiple events could occur within that timeframe, and so a buffer would be required in order to prevent information loss - as Yami points out, you're better off just withholding user-input based events while always resuming with other event types for the duration of your "pause". That's how multishell does it, for example - if you've got a timer-based clock running in one tab, it'll keep running while you're in another, but it won't receive any key/char/key_up/etc events unless they occur while it's the "active" tab.
hbomb79 #14
Posted 02 September 2015 - 08:41 PM
In DynaCode (I just finished adding a manager into my framework) each window has its own object and redirect. Inside the managers loop, whenever it receives an event I tell it to redirect the terminal to that windows redirect, and resume that windows coroutine (stored in the object also). When resuming I pass in the event and all the arguments.

I perform a simple check to see if the window is active or not, if it is not then I will only pass it certain events, otherwise all events will be stopped and function calls like sleep() will never get their timer return and yield forever.

If you want to see the source code, here is a link (around lines 1534 for the coroutine manager and 837 for the terminal redirect.)
Hope it helps

You'll want to handle "filters", like when you call pullEvent(filter). couroutine.resume returns this filter, so check if it has been passed and store that too, making sure that if a filter is set, ONLY pass the event in the filter to this yield.

This is in the link above at line 1592. FYI, in the source pgCo is the coroutine you are interested in, just ignore messageCo its not finished and might confuse you :D/>

*All line numbers are subject to change pretty quick xD
Edited on 02 September 2015 - 06:50 PM