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

Run code "in background"

Started by KingofGamesYami, 06 August 2014 - 03:25 AM
KingofGamesYami #1
Posted 06 August 2014 - 05:25 AM
So, let's say we (theoretically) want to run some code parallel of a main program, but we are making an API. How would you accomplish this? I've stumbled upon the answer.
You will want to have a good understanding of
-os.pullEvent
-coroutines
-functions
-variables
-etc.
before continuing.

Step 1: Make some looping code in a function
Example:

function foo()
  while true do
	local event = { os.pullEvent( "modem_message" ) }
	--#do stuff with it
  end
end
Now, while this code does not seem particularly useful, it can be. You may want to "network" several devices together and listen for the specific events they send.

Step 2: Backup os.pullEventRaw() and create a coroutine

local oldPull = os.pullEventRaw --#note the lack of parentheses
local coFoo = coroutine.create( foo ) --#note "foo" does not have parentheses

Step 3: Overwrite os.pullEventRaw()

function os.pullEventRaw( sFilter )
  while true do
	local event = { oldPull() } --#note I am using the backup
	if coroutine.status( coFoo ) == "suspended" then --#we to make sure it is not our function (now a coroutine) calling it.
	   coroutine.resume( coFoo, unpack( event ) ) --#unpack( tbl ) returns the contents of the table.
	end
	if sFilter == event[ 1 ] or not sFilter then --#if the event is the correct type, or there is no filter;
	  return unpack( event )
	end
  end
end

If you wished, you could even have this iterate through different coroutines. I suspect you could also write a function to insert additional coroutines into the program, but I think it would be highly unnecessary.

Questions? Comments?
Engineer #2
Posted 06 August 2014 - 12:41 PM
You would want to override coroutine.yield, because that is the real os.pullEventRaw()
KingofGamesYami #3
Posted 06 August 2014 - 10:48 PM
You would want to override coroutine.yield, because that is the real os.pullEventRaw()
I hesitate to overwrite coroutine functions as I don't fully understand them.
theoriginalbit #4
Posted 07 August 2014 - 01:54 AM
coroutine.yield is the same as the pull events, that's actually what they use. Perhaps you should get an understanding of that and improve upon your tutorial, at the moment it is a little lacking, not quite to the standard we are looking for in a tutorial. Take a look at Lyqyd's or my own tutorials for the Ask a Pro series to see the rough standard we are looking for in tutorials.
KingofGamesYami #5
Posted 07 August 2014 - 06:14 AM
coroutine.yield is the same as the pull events, that's actually what they use. Perhaps you should get an understanding of that and improve upon your tutorial, at the moment it is a little lacking, not quite to the standard we are looking for in a tutorial. Take a look at Lyqyd's or my own tutorials for the Ask a Pro series to see the rough standard we are looking for in tutorials.
Yeah, I know what coroutine.yeild does, but I'm more concerned as of where it may be used other than in os.pullEvent. What program would use coroutine.yield in place of os.pullEvent anyway?

About the tutorial: Yeah I know it's pretty quick. I wrote it in 5 minutes, but I figure if someone understands coroutines, they can understand what I'm doing in the examples. I'll update it when I find the time. (might be a while, school's starting)
Engineer #6
Posted 11 August 2014 - 10:56 PM
coroutine.yield does get called when you call os.pullEvent. os.pullEvent calls os.pullEventRaw and os.pullEventRaw only returns coroutine.yield(), so that meas the coroutine.yield is the first layer of the events. When you overwrite coroutine.yield, nobody else can manipulate you, because I can still manipulate you when i override coroutine.yield!

Do you catch my drift?
skwerlman #7
Posted 12 August 2014 - 02:20 PM
So basically:
Event -> coroutine.yield -> os.pullEventRaw -> os.pullEvent
Did I get that right?
theoriginalbit #8
Posted 12 August 2014 - 04:13 PM
yep.

from bios.lua

function os.pullEventRaw( sFilter )
  return coroutine.yield( sFilter )
end

function os.pullEvent( sFilter )
  local eventData = { os.pullEventRaw( sFilter ) }
  if eventData[1] == "terminate" then
    error( "Terminated", 0 )
  end
  return unpack( eventData )
end
Ferdi265 #9
Posted 28 August 2014 - 11:56 AM
I wrote an API that does this and a bit more. I could link this as a kind of partial explanation.

My API iterates over coroutines and resumes them if the current event passes a filter that is stored along with the coroutine. (E.g. You coupd have a coroutine that only resumes on 'rednet_message' and one that resumes on all events.)

It also exposes functions to add coroutines at runtime, and one for adding repeatable event listeners.

http://www.computercraft.info/forums2/index.php?/topic/20160-computercraft-eventloop-a-powerful-api-for-event-handling/page__pid__192375#entry192375

Sorry for the ugly link, I'm on mobile.
electrodude512 #10
Posted 01 September 2014 - 03:44 AM
You might want to put your function in a pcall so you can restore the real coroutine.yield in case the function dies, so the whole computer doesn't crash.
Kouksi44 #11
Posted 07 November 2014 - 09:33 PM
This is exactly wht I need for my new project :)/>

Only problem is that I do not fully understand the code !

My main problem is, taht we create a coroutine but then we do not resume it.

I thought you have to resume a coroutine right after creating in order to run the function ?

Would be very nice if someone could explain this to me !

Thank you in advance

Kouksi44
theoriginalbit #12
Posted 08 November 2014 - 01:01 AM
-snip-
you can resume it whenever you wish to run the coroutine, in this case it is being run inside the loop. However since it is yielding before it resumes the coroutine, you should probably resume it after you create it, that way it can run up to a yield point and be ready to receive events. You should probably take a look at Bubba's Coroutine Tutorial :)/>

-snip-
Second reminder, please update/improve this tutorial, it is seriously lacking in explanations, and does contain some questionable content. It isn't to the standard we're looking for, please take a look at Lyqyd's or my own tutorials for the Ask a Pro series to see the rough standard we are aiming for in tutorials.
mentalr0b123 #13
Posted 22 February 2015 - 12:25 PM
there is a background program

--Background Rednet Listener--
rednet.open("left")
function listen()
while true do   
    id , msg = rednet.receive()
    if msg == "shutdown" then
		   os.shutdown()
    end
end
end
function toBackground()
    shell.run("/rom/programs/advanced/multishell")
end
--İts working only advanced computers...--
parallel.waitForAny(toBackground , listen)
its working on background.
Bomb Bloke #14
Posted 23 February 2015 - 12:43 AM
Mind you, if you're going to use multishell, you also have the option of using the instance that's already running.

Eg, just:

rednet.open("left")

while true do   
    id , msg = rednet.receive()
    if msg == "shutdown" then
                   os.shutdown()
    end
end

Then at the CraftOS command prompt, launch it via:

bg <scriptName>
thecrimulo #15
Posted 05 July 2016 - 06:26 PM
Mind you, if you're going to use multishell, you also have the option of using the instance that's already running.

Eg, just:

rednet.open("left")

while true do  
	id , msg = rednet.receive()
	if msg == "shutdown" then
				   os.shutdown()
	end
end

Then at the CraftOS command prompt, launch it via:

bg <scriptName>
So, if i wanted to run something in the background on an advanced comuter, i can just do shell.run("bg", "myscript")?
Lyqyd #16
Posted 05 July 2016 - 07:29 PM
Yes, that's correct.
Bomb Bloke #17
Posted 06 July 2016 - 01:52 AM
Though it'd be more elegant to use shell.openTab("myscript").
thecrimulo #18
Posted 06 July 2016 - 01:14 PM
And what about programs that paint to the screen (like an OS' desktop) or detect keyboard presses? Easy multitasking would be great
HDeffo #19
Posted 07 July 2016 - 10:46 AM
And what about programs that paint to the screen (like an OS' desktop) or detect keyboard presses? Easy multitasking would be great

Plenty of very simple multi tasking APIs on buried on the forums. The issue is when someone really needs a multi tasking API they have usually gotten to the point they can make it themselves and don't want to use someone else's code. Because of that the multitasking threads tend to get pretty buried and hidden. I have one that runs off a single function call made to be as similar to the parallel API as possible. I believe yami has one somewhere that's actually very unique that creates a task queue of sorts (if I read and remember the program's description right). If you really need something like that and don't have the ability to code it you can definitely find it here somewhere just need to look.
KingofGamesYami #20
Posted 07 July 2016 - 01:53 PM
I believe HDeffo is referring to this API I wrote.