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

Concurrent Access with Parallel API

Started by drummerp, 20 July 2013 - 05:48 PM
drummerp #1
Posted 20 July 2013 - 07:48 PM
Hi, guys, old Lua scripter here, but new to ComputerCraft. I seem to be having problems with writes from one parallel function not being read by the other. I'm using parallel.waitForAll() with two functions that run forever ("while true do" loops). I have a variable that was declared outside of the functions, in the script's scope. One function waits for rednet input, then adjusts the variable's value. The other function loops and reads the variable's value, using it to display text on a monitor. The issue is, the value never changes. Although the write is clearly successful in one thread, it fails in the other. Here is a snippet of my code to show what I mean:


local rooms = {true, true, true, true} --true = unoccupied, false = occupied; all rooms start off occupied
rednet.open("top")
monitor = peripheral.wrap("right")
monitor.setTextScale(2.5)
term.redirect(monitor)

function listen() --waits for rednet input, then writes to "rooms" table
	while true do
		id, mes = rednet.receive(nil)
	    local room = string.sub(mes,1,-2)
	    local open = tonumber(string.sub(mes,-1,-1))
		write("Room " .. room .. " is now ") --Debug check
		if open > 0 then
			print("open!")
			rooms[room] = true
		else
			print("closed!") --This does, in fact, print
			rooms[room] = false
		end
		print("The value at index " .. room .. " is now " .. tostring(rooms[room])) --Sanity check: it does print false
		sleep(5) --Shouldn't get messages too frequently
	end
end

function display() --Reads table, displays on monitor
	while true do
	    term.setBackgroundColor(colors.black)
	    term.clear()
	    term.setCursorPos(1,1)
	    for i=1,#rooms do
		    print("The value at index " .. i .. " is " .. tostring(rooms[i])) --Sanity check: always prints true!
		    term.setBackgroundColor(colors.black)
	        term.setTextColor(colors.white)
		    write("Room " .. i .. ": ") --Actual display
		    if rooms[i] then
			     term.setBackgroundColor(colors.green) --Always gets printed, even after claiming to have closed the room
		   	  term.write("Empty")
			 else
		        term.setBackgroundColor(colors.red)
			    term.write("Taken")
	        end
		    term.setBackgroundColor(colors.black)
		    print(" (" .. tostring(rooms[i]) .. ")") --Final sanity check: also always prints true!
	    end
	    sleep(10) --Will be decreased, but currently high for debugging purposes
    end
end

parallel.waitForAll(listen, display)

Even after it receives a rednet signal that one room has closed, it continues to show "open" and "true". Here are pictures to demonstrate:


Upon startup


Right after closing one room (display hasn't updated the screen yet)


After display() updates the screen again

Is this a problem with the parallel API itself, or am I just doing something wrong?
Lyqyd #2
Posted 20 July 2013 - 11:20 PM
Split into new topic.

Please post the whole code.
drummerp #3
Posted 22 September 2013 - 10:03 PM
Split into new topic.

Please post the whole code.

The main post has been edited to display the full script.
drummerp #4
Posted 10 November 2013 - 10:37 AM
I apologize for what must seem a useless post, but I still require assistance on this topic.
Yevano #5
Posted 10 November 2013 - 11:49 AM
In the listen thread, you're setting room to a string. Then, you use it as the index to rooms. The display thread fails to read the index because it looks for number indices. Convert room to a number before you use it to index rooms. That is,


rooms[tonumber(room)] = false

Also, you shouldn't sleep in your listen thread, since this can cause you to miss rednet events which are sent less than 5 seconds after the last.
Edited on 10 November 2013 - 10:51 AM
drummerp #6
Posted 10 November 2013 - 11:54 AM
In the listen thread, you're setting room to a string. Then, you use it as the index to rooms. The display thread fails to read the index because it looks for number indices. Convert room to a number before you use it to index rooms. That is,


rooms[tonumber(room)] = false

Also, you shouldn't sleep in your listen thread, since this can cause you to miss rednet events which are sent less than 5 seconds after the last.

Wow, that's…disappointingly simple. Thank you! I'll test this as soon as I get the chance.

Is rednet.receive sufficient to replace the sleep, then, since it's blocking? I just wanted to ensure that I wasn't running the thread too much.
Yevano #7
Posted 10 November 2013 - 12:40 PM
Is rednet.receive sufficient to replace the sleep, then, since it's blocking? I just wanted to ensure that I wasn't running the thread too much.

That's correct. As a basic rule of thumb, you usually don't need to sleep as long as you're pulling events. And as a guideline, try not to write code which relies on busy polling that requires short sleeps.