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

[Question] Thread-safe Sleep function

Started by angellus, 26 May 2013 - 05:19 PM
angellus #1
Posted 26 May 2013 - 07:19 PM
I did a search and there were *some* related post, but none directly addressed what I need and would of taken probably an hour or so just to read through all the topics. So, here is what I need: some people might already know that when you use the parallel and coroutine APIs to do threading some functions do not work right. The only one I know about is "os.sleep()". I have done a little big of parallel computing in C++ and I know some functions are just not thread-safe. Is there a way to make a thread-safe version of sleep? Or is there one out there?
Lyqyd #2
Posted 26 May 2013 - 08:13 PM
What on earth are you talking about?
angellus #3
Posted 26 May 2013 - 09:23 PM
http://computercraft.info/wiki/Coroutine_(API)

Read down at the bottom. "Interaction with Other APIs". You can use parallel and coroutine can let you multithread things so you can run multiple things at once. I am working on a more advanced shell that lets me run programs in the background and switch between them along with scrolling and other fun features.
Lyqyd #4
Posted 26 May 2013 - 10:40 PM
You will not encounter any problems if you use coroutines in the usual manner (the event-based model). That section of the coroutines page is highly misleading in its wording.
angellus #5
Posted 26 May 2013 - 10:54 PM
Sleep does not work for me when I use coroutines.
Lyqyd #6
Posted 26 May 2013 - 11:05 PM
Would you mind posting your coroutine manager? I would suspect that you're doing something other than using it like the event-based model ComputerCraft generally uses. If your coroutine manager can't handle sleep, it won't be able to handle running regular ComputerCraft programs in the background, FYI. It would be better to improve/fix your coroutine manager rather than try to replace sleep and all of the other functions that would break your coroutine manager.
angellus #7
Posted 26 May 2013 - 11:24 PM
I just do the simplest coroutine and the sleep inside of it does not work:


bgProg = coroutine.create(os.run)
coroutine.resume(bgProg, tEnv, sPath)

This is inside of a shell program and I am overwriting the shell program completely, so I am using os.run not shell.run. sPath is just the path to a simple program I made that is the following:


count = 1
while count < 10
	print("Testing... (" .. count .. ")")
	sleep(1)
end

The output is only the first line:

Testing… (1)
Bubba #8
Posted 26 May 2013 - 11:51 PM
You're only resuming it once. Sleep employs timers and os.pullEvent, and os.pullEvent is just a wrapper for coroutine.yield. So as soon as you call sleep, you are yielding back to the main program.

You'll have to employ a while loop with your coroutine.resume until coroutine.status returns "dead". You'll also have to handle sleeping on the outside of the coroutine by pulling the timer event from the caller. A bit like this:

local function example()
  for i=1,10 do
	print("Test: "..i)
	sleep(1)
  end
end

local co = coroutine.create(example)
local evt = {}
while coroutine.status(co) ~= "dead" do
  local ok, param = coroutine.resume(co, unpack(evt))
  evt = {os.pullEvent()}
end
angellus #9
Posted 27 May 2013 - 12:30 AM

local evt = {}
while coroutine.status(co) ~= "dead" do
  local ok, param = coroutine.resume(co, unpack(evt))
  evt = {os.pullEvent()}
end

Would the coroutine fire an event when it returned? That os.pullEvent would not return unless it did. Also, how would I resume it with additional input parameters and be able to put in the event too? So like if I was trying to do the os.run and I needed to pass in the args, but still then resume later with the event?

Thanks by the way. Like Lyqyd said, the page can be misleading and I missed from of it. Haha
Lyqyd #10
Posted 27 May 2013 - 02:56 AM
Arguments are passed in on the very first resume. Where you have local evt = {}, below that you'd have a line that fills in any arguments passed to it initially, just before you enter the while loop.

Not sure what your question about the coroutine firing an event when it returned refers to. The whole "event" concept is entirely based on parameters passed in when the coroutine is resumed, so whatever parameters you pass in show up to the coroutine as an "event"; it's up to you to make sure your coroutines understand what you're passing them. That's why coroutine managers usually just distribute events. The example code Bubba provided should function fine, but will only manage a single coroutine. You might find it valuable to read through the parallel API to see how it works. Look in the Computercraft.zip, under lua/rom/apis/parallel. Any text editor can open it.
angellus #11
Posted 27 May 2013 - 08:55 AM
Thanks. Sorry if that last question was unclear, It checks to see if the coroutine is dead until it is, right? Well, the last line in the loop, "evt = {os.pullEvent()}", if the corountine becomes dead and it does not throw an event to say so, they will block there forever, won't it? So my question was, will it throw an event when the coroutine returns? To exit that block and end the loop. Also, I will look into the parallel API, thanks. Never thought to look there, I already overwrote alot of the code from the shell file and some from the bios (well, only "read()" and "os.getVersion()").
Lyqyd #12
Posted 27 May 2013 - 12:37 PM
The coroutine will automatically yield when it dies. Yes, the way it is written, the coroutine manager will grab an extra event before exiting the resume loop. The manager in the parallel API (which I again strongly recommend reading) does not have that problem.
Bubba #13
Posted 27 May 2013 - 12:52 PM
I've made a tutorial on coroutines which may help you with what you're trying to do. It is located on Google Drive here. Alternatively, you can check out the forum topic here (sorry if this seems like shameless self-promotion - that's not my goal). In the tutorial I give a more in-depth explanation of how coroutines work and how you can achieve basic multi-tasking. I would also recommend checking out coroutines on the Lua PIL.


Like Lyqyd said though, you should definitely check out the parallel API - it helped me when I was first getting into creating a coroutine manager.
angellus #14
Posted 27 May 2013 - 04:35 PM
Tutorials are never self-promotion. Put them in your sig so if anyone interested sees them, they can check them out. Kaos has his utilities in his sig and they have been a huge help. He helped me get what I got done so far and I am using a modified version of his Layer API for terminal output redirection. Hell, put them on the wiki. The wiki can always use more documentation. I try to use it and Google before coming here for answers.
Hawk777 #15
Posted 28 May 2013 - 04:22 AM
You will not encounter any problems if you use coroutines in the usual manner (the event-based model). That section of the coroutines page is highly misleading in its wording.

As the author of that section, I respectfully object to it being described as “highly misleading”. If you look at introductions to coroutines in general on the Internet, you generally end up reading about something like a lockstep producer-consumer pair. If you built something like that (a supposedly typical example of what coroutines would be used for) using Lua coroutines in ComputerCraft and then called a blocking API function from one of those coroutines, it would explode spectacularly. Yes, there are cases where you can use the blocking routines from inside raw coroutines safely, but those cases are very limited—namely, only if your coroutines happen to be dispatched by events from the system event queue, which is just one possible case out of many. Also, I do mention at the bottom of that section that one option is to “arrange to handle event dispatch the same way that the parallel API does so that the blocking functions work properly”.

Perhaps any further discussion of this should be taken to the talk page on the wiki, if you feel there is something that should be changed? I see you added a NeedsWork template, but didn’t actually explain what the problem was.
Lyqyd #16
Posted 28 May 2013 - 01:10 PM
I've added the reasoning to the talk page; we can discuss it further there.