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

Coroutines and Eventrelay

Started by Subb, 15 March 2013 - 01:44 AM
Subb #1
Posted 15 March 2013 - 02:44 AM
Hello there,
i'm using computercraft and lua for about a week now and i'm starting to use coroutines.

a simple version of the problem i encountered:

mylib

function setup(job)
	 -- do stuff
	  work = coroutine.create(job)
	 --do more stuff
	while true do
		 local TEvents = {os.pullEvent() }
		 coroutine.resume(work, unpack (TEvents) )
		Uplink() --a funktion working perfectly fine
	   sleep(1)
	 end
end

runMe

os.loadAPI(mylib)
function job()
	while true do
		sleep(0.1)
		turtle.turnLeft()
	   end
end

lib.setup(job)

Now the problem i got is a not working Job Function.
The uplink perfectly fine uses his method every second, but the turtle only turns left once.

Well i did seek for an answer before and apartently turtle.turnLeft() does wait for an event to happen - obviously to determine if it turned or not.
Passing TEvents to the coroutine didnt work aswell, altough it looked like it worked in a forumpost for basically the same problem.

Any suggestions what i'm doing wrong?
Lyqyd #2
Posted 15 March 2013 - 05:36 AM
Split into new topic.
GopherAtl #3
Posted 15 March 2013 - 05:42 AM
not seeing anything obviously wrong, what's going on in the uplink function?
Lyqyd #4
Posted 15 March 2013 - 05:45 AM
I would guess that it pulls events, making the turtle wait for its event response forever.
MysticT #5
Posted 15 March 2013 - 05:49 AM
The sleep call is probably pulling the events needed in the job function. You shouldn't use sleep there, if you want the Uplink function to work every second you should use a timer.

function setup(job)
	 -- do stuff
	  work = coroutine.create(job)
	 --do more stuff
	while true do
		 local TEvents = {os.pullEvent() }
		 coroutine.resume(work, unpack (TEvents) )
		Uplink()
	   sleep(1) -- This is the call that "eats" the events
	 end
end
GopherAtl #6
Posted 15 March 2013 - 05:54 AM
mystict, it shouldn't be, each should wait for it's own event before the other runs at all. Sleep eating events is only an issue with events that happen spontaneously, event blocking functions don't interfere with other event-blocking functions in that way. Lyqyd is probably right, which is why I was asking what's in Uplink, as if it eats events, then the coroutine will never get them.
MysticT #7
Posted 15 March 2013 - 06:01 AM
mystict, it shouldn't be, each should wait for it's own event before the other runs at all. Sleep eating events is only an issue with events that happen spontaneously, event blocking functions don't interfere with other event-blocking functions in that way. Lyqyd is probably right, which is why I was asking what's in Uplink, as if it eats events, then the coroutine will never get them.
Are you sure?
Calling os.pullEvent with a filter (like os.pullEvent("timer")) doesn't pull other events?
IIRC it did pull every event until there's one of the requested type. Has this changed?
An example: if you call sleep, and while the computer is sleeping someone clicks on the screen, will you get the "mouse_click" event after the sleep?
Subb #8
Posted 15 March 2013 - 06:01 AM
Thanks alot for the replys guys o/

So first i tried removing the sleep - which would've caused a funny little loop there if os.pullEvent hadn't decided to develop a little blocking ability untill i cause an external event.
(Kind of didnt expect it to, thought thats what pullEventRaw was ment to be for - aanyway i'm loosing focus here… nice hat Gopher)

Bottomline, it doesnt work.
My Uplink function doesnt do alot atm. Basically it wraps the wireless modem and sends out a little Ping. I'm gathering some information from my bots while they're at work.
I assume the idea about the timer is correct, i shouldnt sleep there on the long run but kind of just want to get it working for now :)/>
(for testing reasons the uplink function is commented atm btw :)/> )
GopherAtl #9
Posted 15 March 2013 - 06:06 AM
mystict, I'm sure. First sleep queues a timer, then it waits for the event. Yes, events coming first will be discarded, but turtle.turn can't run until AFTER sleep exits, so there is no turtle event yet to miss. When sleep finally gets it's timer, then turtle runs, and waits for IT'S event. Again, sleep can't even run and start waiting for events until turtle gets it's event.

So the sleep in the job function is not the problem. If there are any sleep(), rednet.receive(), or turtle calls in Uplink, that is the problem.
MysticT #10
Posted 15 March 2013 - 06:12 AM
mystict, I'm sure. First sleep queues a timer, then it waits for the event. Yes, events coming first will be discarded, but turtle.turn can't run until AFTER sleep exits, so there is no turtle event yet to miss. When sleep finally gets it's timer, then turtle runs, and waits for IT'S event. Again, sleep can't even run and start waiting for events until turtle gets it's event.

So the sleep in the job function is not the problem. If there are any sleep(), rednet.receive(), or turtle calls in Uplink, that is the problem.
Well, but I mean the sleep call in the first while loop, not the one inside the function. The first loop used to resume the coroutine, calls sleep at the end, and that's what "eats" the events. See, when the sleep or turtle call inside the function yields to wait for the events (the timer and turtle response), it returns to the first loop, and before pulling events and passing them to the coroutine it calls sleep, wich pulls and discards the events.

I think this should work:

function setup(job)
  -- do stuff
  work = coroutine.create(job)
  --do more stuff
  local timer = os.startTimer(1) -- a timer to call the Uplink function
  while true do
    local TEvents = {os.pullEvent() } -- get the next event
    if TEvents[1] == "timer" and TEvents[2] == timer then -- check if the event is our timer
	  Uplink() -- if it is, call the Uplink function
	  timer = os.startTimer(1) -- and restart the timer
    else
      coroutine.resume(work, unpack(TEvents)) -- otherwise, resume the coroutine
    end
  end
end

I think that you could use parallel to do this easier, like this:

local function Uplink()
  -- do something here
  sleep(1)
end

function setup(job)
  parallel.waitForAny(job, Uplink)
end
A lot easier, isn't it?
Lyqyd #11
Posted 15 March 2013 - 06:14 AM
MysticT is right. You two are looking at different sleep calls. There's a sleep(1) in the coroutine manager. Remove that and the problem should fix itself.
Subb #12
Posted 15 March 2013 - 06:14 AM
Ok, i have to correct myself.

The mainfunctions sleep really ate the event.
Went abit berserk on debugging and changed the event sending itself (stupid me). When i returned it back to normal and still kept the the calling functions sleep removed it began to work.

Yay

thanks!

edit:

And Yes, your code DOES look better than mine :)/>
GopherAtl #13
Posted 15 March 2013 - 06:14 AM
ooh! I didn't even notice that one. Sorry, I'm failing like crazy in this thread…

Yes, the sleep in setup() is definitely a problem, lol.