Below are some simple examples of multi-threaded Lua scripts. As people send me more nice examples, I will add them to this page. It would be interesting to have solutions to the basic IPC problems available here.
This simple program uses two independent threads of execution to flood the terminal with the words "parent" and "child", separated by commas.
local function flood(output, word)
while 1 do
output:lock()
io.write(word, ", ")
output:unlock()
end
end
local output = thread.newmutex()
thread.newthread(flood, {output, "child"})
flood(output, "parent")
A snippet the output could look like the text below:
parent, parent, parent, child, child, child, parent, child, child, child, parent, parent, child, child, child, parent, parent, parent, child, child, parent, parent, child, child, parent, parent, parent, child, parent, ...
Note that if the output mutex was not in use, the result could have included an output such as the following:
parent, parentchild, , parent, child, child, child, parent, child, child, child, parent, parent, childparent, child, child, parent, parent, parent, child, child, parent, parent, child, child, parent, parent, parent, child, parent, ...
That is because between writing the word and the comma, each thread could be preempted and control could be handed to the other thread. This is what the output mutex prevents.
Below is a program solving the classic producer-consumer problem. The code uses a the thread.queue module, which encapsulates all the synchronization:
SIZE = 128
local thread = require("thread")
local queue = require("thread.queue")
local fifo = queue.newqueue(SIZE)
local output = thread.newmutex()
function newcount()
local mutex = thread.newmutex()
local value = 1
return function ()
mutex:lock()
local v = value
value = value + 1
mutex:unlock()
return v
end
end
local count = newcount()
function consumer(fifo, output)
while 1 do
local value = fifo:remove()
output:lock()
io.write("consumer removed ", value, "\n")
output:unlock()
end
end
function producer(count, fifo, output)
while 1 do
local value = count()
fifo:insert(value)
output:lock()
io.write("producer inserted ", value, "\n")
output:unlock()
end
end
-- run consumer function in a new thread
thread.newthread(consumer, {fifo, output})
-- run producer function in the main thread
producer(count, fifo, output)
In summary, the consumer thread loops removing elements from the queue, while the producer thread loops inserting elements. When the queue is empty, the consumer is blocked by the queue until there are more elements available (i.e., until the producer threads inserts a new element). When the queue is full, the producer is blocked by the queue until there is a free slot (i.e., until the consumer removes an element).