Can't understand the principle of Thread and Channel work

Questions about the LÖVE API, installing LÖVE and other support related questions go here.
Forum rules
Before you make a thread asking for help, read this.
Post Reply
Gerhop
Prole
Posts: 1
Joined: Fri Sep 15, 2017 6:51 am

Can't understand the principle of Thread and Channel work

Post by Gerhop »

Hello, guys! Obviously, i'm new to lua language and game development, so i'm trying to get understanding of the basics before doing something more specific. And so far i've got stucked in the thread and channels, and here comes the problems:
First of all, should "thread:start()" be included in "love.update" function to work?
Second, i'm trying to boot thread on main file load, send variable to him; in the thread itself this variable increases, sends back to the main file and displays on 300,300 point... And its simply not working. Can you guys explain me where am i did mistake?
The main file:

Code: Select all

 local e = 0 -- time limitation variable
function love.load()
  vr = 5 -- variable that sends in the thread
  thread1 = love.thread.newThread("menu.lua") -- creating thread
  channel = love.thread.newChannel("channel") -- creating channel (?)
  thread1:start() -- starting thread
  channel:push(vr) -- sending variable to the thread (?????)
  vr = channel:pop() -- receive increased variable from the thread (????)
end

function love.update(dt)
end

function love.draw(dt)
  love.graphics.print(tostring(vr), 300,300) -- draw increased variable on 300.300
end
function love.threaderror(t, e) -- error-capturing function i've found on the internet
    return error(e)
end
Thread:

Code: Select all

require("love") -- including all modules from love (????)
local channel = love.thread.getChannel("channel") -- receive channel from main file
local d = 0 -- variable that will hold sended number
d = channel:pop() -- getting variable from channel (????) after "channel:push(vr)" in the main file (????)
if d == nil then -- d got nothing so without this block love'll give me an error 
d = 393
end
local e = 15 + tonumber(d) -- variable that sends back to the main file
channel:push(e)
-- sending variable back
User avatar
bartbes
Sex machine
Posts: 4946
Joined: Fri Aug 29, 2008 10:35 am
Location: The Netherlands
Contact:

Re: Can't understand the principle of Thread and Channel work

Post by bartbes »

There are a few problems with this code. The big problem is your call to newChannel("channel"). It does not, as you seem to think, create a channel named "channel", it creates an anonymous channel, as newChannel does not accept any arguments. If you use getChannel("channel") instead your thread will at least be using the same channel. An alternative way to send the channel is to create an anonymous channel, but pass it as an argument to thread1:start(), so the thread gets it as an argument it can retrieve with ....

Now they're talking on the same Channel, there's still the issue that you never wait, so it's unlikely any communication will actually happen. The first change there is probably to replace channel:pop() in the thread with channel:demand(), making sure it actually gets a value. In the main thread you can do the same, but that suspends your game, so instead you probably want to pop until you get a result in love.update.

Note that unfortunately with this setup it's still possible your main thread reads your vr (5) again in the pop, there are a few ways around this, mostly by not using the same channel for both directions, or you can use channel:supply(vr) to send it, making sure the main thread doesn't run until the value is read by the other thread. Although it blocks the main thread, of course.
drunken_munki
Party member
Posts: 134
Joined: Tue Mar 29, 2011 11:05 pm

Re: Can't understand the principle of Thread and Channel work

Post by drunken_munki »

This is the code that I have used, adapted to somewhat your example -- the variable will tick up by 1 every half second.

Note that the 'thread' must be started in love.load, and that I have included a timer on both update() and inside the worker thread. The worker thread needs a loop in order to keep 'listening' for more work, otherwise it would just stop itself!

I'm not entirely sure we need timers in the thread itself, so you can lower the tick rate or remove the check completely. I use a thread to save the game data out while the main game is still playable so I only check every second to save cpu cycles.

Also, in this case of using the worker to update that var, we do not really need to send the var back to the worker each update! It depends on what you are doing with it, but really it could be sent once to 'init' the worker thread and the main update could check keep 'pulling' the updated value back. Up to you my friend.

main.lua:

Code: Select all

--- Imports
require "love.timer"

--- Performance binds
local getTime                          = love.timer.getTime
local thread                           = love.thread

--- Configuration
local updateTick                       = 0.5 -- Update every n seconds

--- Local variables
local THREAD                           = thread.newThread("worker.lua") -- Create the worker thread (from lua file)
local channel                          = thread.getChannel("data_from_thread") -- Return
local channel2                         = thread.getChannel("data_to_thread_command") -- Send-to
local var                              = 0
local time0                            = getTime()

--- Functions
function love.load()
  THREAD:start() -- Start the thread
end

function love.update(dt)  
  if (getTime() - time0) > updateTick then -- Update the thread per tick
    
    channel2:push(var) -- Push the current value to the thread
    
    if channel:getCount() > 0 then
      var = channel:pop() -- Update with the message from the return channel
    end
    
    time0 = getTime()
  end  
end

function love.draw()
  love.graphics.print(tostring(var), 300, 300)
end

function love.threaderror(t, e)
  return error(e)
end

worker.lua:

Code: Select all

--- Imports (a separate thread requires its own modules)
require "love.timer"

--- Performance binds
local getTime                          = love.timer.getTime
local thread                           = love.thread

-- Configuration
local updateTick                       = 0.5 -- Update every n seconds

--- Local variables
local channel                          = thread.getChannel("data_from_thread")
local channel2                         = thread.getChannel("data_to_thread_command")
local time0                            = getTime()

--- Thread loop
while true do  
  -- Update the thread per tick, and if the channel has any messages
  if (getTime() - time0) >= updateTick and channel2:getCount() > 0 then
  
    local d = channel2:pop() -- Value from channel
    
    -- Whatever you need to do with the value in this update
    d = d + 1
    
    channel:push(d) -- Return the value
  
    time0 = getTime() -- Reset time marker
  end  
end
Post Reply

Who is online

Users browsing this forum: No registered users and 7 guests