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

Question about parallel API functions

Started by diegodan1893, 29 December 2012 - 07:12 AM
diegodan1893 #1
Posted 29 December 2012 - 08:12 AM
In parallel API, the function who do the multitask stuff is this:


function runUntilLimit( _routines, _limit )
	local count = #_routines
	local living = count
  
	local tFilters = {}
	local event, p1, p2, p3, p4, p5
	while true do
	 for n=1,count do
	  local r = _routines[n]
	  if r then
	   if tFilters[r] == nil or tFilters[r] == event or event == "terminate" then
		local ok, param = coroutine.resume( r, event, p1, p2, p3, p4, p5 )
	 if not ok then
	  error( param )
	 else
	  tFilters[r] = param
	 end
	 if coroutine.status( r ) == "dead" then
	  _routines[n] = nil
	  living = living - 1
	  if living <= _limit then
	   return n
	  end
	 end
	end
	  end
	 end
  for n=1,count do
	  local r = _routines[n]
   if r and coroutine.status( r ) == "dead" then
	_routines[n] = nil
	living = living - 1
	if living <= _limit then
	 return n
	end
   end
  end
	 event, p1, p2, p3, p4, p5 = os.pullEventRaw( )
	end
end

Based on this function I'm writing my own multitask function:


function start() -- TODO Make this local
local tFilters = {}
local event, p1, p2, p3, p4, p5

while true do
  for i = 1, #tThreads, 1 do
   r = tThreads[i]
  
   if r ~= nil then
	if tFilters[r] == nil or tFilters[r] == event or event == "terminate" then
	 local ok, param = coroutine.resume(r, event, p1, p2, p3, p4, p5)
	 if not ok then
	  yError(param)
	 else
	  tFilters[r] = param
	 end
	end
   end
  
   if r and coroutine.status(r) == "dead" then
	table.remove(tThreads, i)
	if #tThreads <= 0 then
	 return i
	end
   end
  end
  for i = 1, #tThreads, 1 do
   r = tThreads[i]
   if r and coroutine.status(r) == "dead" then
	table.remove(tThreads, i)
	if #tThreads <= 0 then
	 return i
	end
   end
  end  
  event, p1, p2, p3, p4, p5 = os.pullEventRaw( )
end
end

They are very similar but my function stop the program until a event is fired because of the os.pullEventRaw at the end, and I don't know why this is not happening in the parallel API function.

My question is how to make the function don't wait for the event and why this is not happening in the other function.
Lyqyd #2
Posted 29 December 2012 - 08:21 AM
It does wait for the next event to fire in the parallel API. What made you think it wasn't?
diegodan1893 #3
Posted 29 December 2012 - 08:32 AM
It does wait for the next event to fire in the parallel API. What made you think it wasn't?
Thanks for answering but I think that because if I do:

a = function() print("hello") end
b = function() print("world") end
kernel.addProcess("testA", a) --A custom function that does the same as create(...) in parallel with the second parameter.
kernel.addProcess("testB", B)/>
kernel.runUntilLimit(kernel.tThreads, 0) --I copied the function to my api. kernel.tThreads is a table with the thread variables created in kernel.addProcess()
It prints:
Hello
World

But if i do this:

a = function() print("hello") end
b = function() print("world") end
kernel.addProcess("testA", a) --A custom function that does the same as create(...) in parallel with the second parameter.
kernel.addProcess("testB", B)/>
kernel.start() --My custom function
It prints:
Hello
*Wait for a event*
World
GopherAtl #4
Posted 29 December 2012 - 08:47 AM
you're checking and removing dead coroutines from your table twice, one in the loop that runs routines and again after that loop before fetching the next event. You should remove the first one. What's happening in your function:

-while loop begins
-for loop begins with n==1
-routine 1 is run, and exits
-routine 1 is removed from the table; routine 2 is now moved up to index 1.
-for loop goes to n==2, which will be nil
-the if r==nil test prevents it from throwing an error, but routine 2, which is now routine 1, doesn't get run
-pullEventRaw waits for a new event.
Lyqyd #5
Posted 29 December 2012 - 08:50 AM
This is because (as far as I can tell) your function is missing an end, but I suspect that the end is misplaced rather than missing, which places your event pull in the for loop that iterates over the threads, rather than in the while loop where it belongs. Hence, your function is pulling a new event for each thread, rather than pulling a new event after it has passed all of the threads the previous event.

Edit: Gopher is probably more right than I am; that's what I get for trying to read code on my phone.
diegodan1893 #6
Posted 29 December 2012 - 09:08 AM
You're right, the problem is solved. I don't know why the function in parallel API checks for dead coroutines twice, it works well with only one. Now with this function I can do the same as waitForAll but I can add and kill processes when I want (only if they yields, but most of them are loops with event listeners, so they yield)
GopherAtl #7
Posted 29 December 2012 - 05:42 PM
The one in the parallel api only sets it to nil on the first check, then deletes it on the second, which is why it works when yours did not.
As to why, it allows it to exit immediately after one routine terminates, if _limit is greater than 0, as it is when waitForAny is used instead of waitForAll.