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).