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

Program Hanging Up and Not Working

Started by CastleMan2000, 21 April 2014 - 10:48 PM
CastleMan2000 #1
Posted 22 April 2014 - 12:48 AM
Hello. I am making a chat program for pocket computers, but it hangs up as soon as you send anything on chat, and messages are not received between computers. Could someone please help fix my code?

http://pastebin.com/aM7f7rBg
Bomb Bloke #2
Posted 22 April 2014 - 12:59 AM
The parallel functions take functions as parameters. If you try and call those functions and pass the results, it's not gonna work. Get rid of the brackets after peerchat.get and peerchat.sendStuff on line 51.

You also can't readily get returned values from those functions (nor do you appear to even try), so the return statement on line 42 is sending that data off into the void. Make the peerchat.get function act on the data it receives.
CastleMan2000 #3
Posted 22 April 2014 - 01:20 AM
The parallel functions take functions as parameters. If you try and call those functions and pass the results, it's not gonna work. Get rid of the brackets after peerchat.get and peerchat.sendStuff on line 51.

You also can't readily get returned values from those functions (nor do you appear to even try), so the return statement on line 42 is sending that data off into the void. Make the peerchat.get function act on the data it receives.
Oh goodness. I did forget to actually make get do something. I kind of forgot that it returned things, and didn't just act on its own. I'll try those, thanks.

Updated the code, now it hangs up upon input, i.e. press T and it stops working properly.
Bomb Bloke #4
Posted 22 April 2014 - 01:29 AM
Ah, that'll be your use of "parallel.waitForAny()". Once either of the functions you pass it finish, it stops the other - then the while loop it's sitting in results in both being restarted from their beginnings. And that rednet.receive() call you've got there is sporting a half-second time out, so…

Perhaps put while loops in your get and sendStuff functions, so that neither may finish. Remove the rednet time-out, and instead use a boolean variable to communicate between the two functions as to when it's safe to write received messages.
CastleMan2000 #5
Posted 22 April 2014 - 01:46 AM
Ah, that'll be your use of "parallel.waitForAny()". Once either of the functions you pass it finish, it stops the other - then the while loop it's sitting in results in both being restarted from their beginnings. And that rednet.receive() call you've got there is sporting a half-second time out, so…

Perhaps put while loops in your get and sendStuff functions, so that neither may finish. Remove the rednet time-out, and instead use a boolean variable to communicate between the two functions as to when it's safe to write received messages.

I don't understand what you mean. Could you elaborate?
Bomb Bloke #6
Posted 22 April 2014 - 02:09 AM
Your "get" function is rigged to always finish within about half a second.

parallel.waitForAny() is rigged such that if one of the functions you pass it ends, then it'll automatically kill the other one.

Hence once you press T, you've only got a very short amount of time to get your message typed in - fail, and it goes back to waiting for you to press T again.
Grim Reaper #7
Posted 22 April 2014 - 02:13 AM
As Bomb Blokes statement might suggest, If you remove that timeout on your rednet.receive call, things should work normally, I think.
Edited on 22 April 2014 - 12:14 AM
CastleMan2000 #8
Posted 22 April 2014 - 02:28 AM
Alright. That's the last update I'll make tonight to the program, and it seems to work! Thank you!
Bomb Bloke #9
Posted 22 April 2014 - 02:33 AM
Nah, "just" removing the timeout isn't sufficient. If a message is received while you're typing the "get" function will still force the "sendStuff" function to end pre-maturally.

You've gotta rig things so that receiving messages will never interrupt sending them. Switching to "parallel.waitForAll()" won't cut it either, as then you'll only be able to receive one message for every one you send - you need to implement loops inside "get" and "sendStuff".

I'm off to work now, have fun. :)/>
CastleMan2000 #10
Posted 22 April 2014 - 02:39 AM
Nah, "just" removing the timeout isn't sufficient. If a message is received while you're typing the "get" function will still force the "sendStuff" function to end pre-maturally.

You've gotta rig things so that receiving messages will never interrupt sending them. Switching to "parallel.waitForAll()" won't cut it either, as then you'll only be able to receive one message for every one you send - you need to implement loops inside "get" and "sendStuff".

I'm off to work now, have fun. :)/>
Oh, I actually noticed that. While sending a message, get did interrupt it. Which might be a problem for large chats. I can't really think how to fix that, this parallel stuff is starting to make my head spin, if you know what I mean.
Edited on 22 April 2014 - 12:40 AM
Grim Reaper #11
Posted 22 April 2014 - 06:52 AM
Well, since I'm not exactly the most well-rested or focused to find a tested and eloquent solution to this problem, here's one that might work:

mainLoop = function()
    local getThread  = coroutine.create (peerchat.get)
    local sendThread = coroutine.create (peerchat.sendStuff)

    while coroutine.status (getThread) ~= "dead" and coroutine.status (sendThread) ~= "dead" do
        local eventData = { os.pullEvent() }

        coroutine.resume (getThread, unpack (eventData))
        coroutine.resume (sendThread, unpack (eventData))
    end
  end

I've never really used the parallel API for any reason in particular, but I think that this example might help you understand coroutines a little better.

In this example the main loop is capturing the actual event data returned by os.pullEvent and is then passing those data to the 'get' and 'send' threads. These coroutines yield control back to the main function when they use coroutine.yield. Since coroutine.yield is what os.pullEventRaw is, the functions yield back when they try to pull an event. This way, the main loop can distribute events to both the threads while they only execute bits of their code before they wait for the next event.
CastleMan2000 #12
Posted 22 April 2014 - 12:00 PM
What does unpack() do?
Bomb Bloke #13
Posted 22 April 2014 - 12:24 PM
You know how you can do something like this?:

function moo()
  return 1,2,3,4
end

unpack lets you achieve the same result from a table:

function moo()
  myTable = {1,2,3,4}
  return unpack(myTable)
end

The code Reaper's got there is a basic outline of parallel.waitForAny().
CastleMan2000 #14
Posted 22 April 2014 - 09:05 PM
Alright, but what about read()? Would I have to have some sort of simultaneous reimplementation? Or do I just have to worry about making get not interrupt sendStuff?
electrodude512 #15
Posted 22 April 2014 - 09:48 PM
Alright, but what about read()? Would I have to have some sort of simultaneous reimplementation? Or do I just have to worry about making get not interrupt sendStuff?
Read() is usually waiting on a os.pullEvent, so the already-existing version will work with coroutines.
Bomb Bloke #16
Posted 23 April 2014 - 01:18 AM
Read() is usually waiting on a os.pullEvent, so the already-existing version will work with coroutines.

Not in this particular case. The problem, as I'm assuming Castle has figured out, is the cursor - if you try to print a received message while the user is in the middle of typing something for read(), it'll mess up.

Alright, but what about read()? Would I have to have some sort of simultaneous reimplementation? Or do I just have to worry about making get not interrupt sendStuff?

Up to you; there's many ways to skin a cat.

You could make your own version of read, which performs constant checks to ensure the cursor is in the correct position. While most complex, this way would remove all need to use coroutines.

You could rig the receiving function to never print messages while a read() is in progress, by storing them in a table or something and printing its contents later.

Or you could just rig the receiving function to always put the cursor back where it found it after printing something. This'd be easiest, at this point.

Again, in case it's not clear, you'll find things a lot simpler if you rig your get / sendStuff functions to never end.