Ok, here the zip file. I didn't make a .love but you can run this the normal way.
Also side note, the conf file is for 0.10.2 so if you're on 11 go ahead and copy the conf from here:
https://love2d.org/wiki/Config_Files
And change console = true (if you're on windows), and vsync = true just to limit the fps the easy way.
So now I'm gonna go through the important part of my code step by step:
Code: Select all
local thread -- Our thread object.
local receiveLine = love.thread.getChannel( "sendLine" )
local threadAction = love.thread.getChannel( "action" )
function love.load()
thread = love.thread.newThread( "threadRead.lua" )
end
We create local variables for our thread and two of our channels. The sendLine channel stored in receiveLine will be used to receive the lines read from the files from the thread. The action thread is used to notify when the thread is over, although it really isn't necessary since we can just use thread:isRunning().
We load the thread code using newThread and the directory of the lua file.
Code: Select all
function love.update(dt)
imgui.NewFrame()
-- Make sure no errors occured.
local error = thread:getError()
assert( not error, error )
if Working then
local threadIsDone = threadAction:pop() or not thread:isRunning()
if threadIsDone then Working = false end
local received = receiveLine:pop()
if received then
print(received)
end
end
miniTimer = miniTimer + 1
if miniTimer == 20 then
freezeNumber = freezeNumber + 1
freezeNumber = freezeNumber % 100
end
miniTimer = miniTimer % 30
end
The two lines below the Make sure no errors occured are very important. They will notify you if something went wrong in the thread. Without those you wouldn't know. When I think about it, that code can be put in the 'if Working' block, since if it's not Working the thread wouldn't be running as well.
Code: Select all
local threadIsDone = threadAction:pop() or not thread:isRunning()
if threadIsDone then Working = false end
This is self explanatory. The only change I would make was add an else and put the rest of the block inside it. But it doesn't matter.
Code: Select all
local received = receiveLine:pop()
if received then
print(received)
end
We pop from the receiveLine channel (a channel is essentially a queue, a first in - first out data structure). If there's nothing, we'll have nil in received so we check for that.
The miniTimer code is to visualise if the game freezes while reading.
Code: Select all
function love.draw()
--drawing stuff
if imgui.Button("Read files") then
if Working == false then
Working = true
thread:start()
end
end
imgui.Render()
love.graphics.print(freezeNumber)
--drawing stuff
end
We start the thread using the method :start. You can find the methods for channels and threads here:
Channel
Thread
threadRead.lua
Code: Select all
require 'love.filesystem'
local channel = {}
channel.sendLine = love.thread.getChannel( "sendLine" )
channel.action = love.thread.getChannel( "action" )
print("Started reading")
local Files = love.filesystem.getDirectoryItems("data")
for iFiles = 1, #Files do
for Line in love.filesystem.lines("data/" .. Files[iFiles]) do
--read lines
channel.sendLine:supply(Line)
end
end
channel.action:push(true)
We load the love.filesystem module because on a thread, only the love.thread module is loaded and if we need any love modules we can just require them like so. This time I decided to store the channels in a table, I find it more readable this way.
I use the :supply method to send the Line over to the main thread. The other method is push, but there's a catch - if you use push and the main thread is busy, the Lines will fill up the queue and use a lot of memory. This memory won't be freed and considering you're reading lots of files I figured supply would be better. What supply does is it sends a message to a thread Channel and wait for a thread to accept it as opposed to the push which just sends the message and continues the operation. Using push in this case won't freeze the thread waiting for the main thread to accept the message but may use a bit more memory.
At the end I send a simple boolean through the action channel to notify we're done. As I said earlier this isn't necessary since we can just use thread:isRunning() but I did it to show that you can have many channels in a thread.
Hope this helped, I'm pretty bad at writing tutorials but this should help you a little.