Lua - Chaining Coroutines using Queue



Using Queue can greatly simplify the coroutine chaining and make them loose coupled as well. One coroutine can send a message to the queue while another coroutine can wait on the queue to read the message and act accordingly.

Example - Chaining Using a Queue

A queue will act as channel for messages between coroutines as shown below:

Define a queue and send/receive operations

-- queue as empty table
local queue = {}

-- send message will add a message to the queue
function send(message)
   table.insert(queue, message)
end

-- to receive a message from Queue
function receive()
   -- if queue has message
   if #queue > 0 then
      -- remove first entry and return the same  
      return table.remove(queue, 1)
   end
   -- yield the current coroutine if queue is empty
   return coroutine.yield() 
end

Create Producer and Consumer Coroutines Functions

function Producer()
   print("Producer Coroutine started")
   send("Message 1 from producer")
   coroutine.yield() -- yield the producer coroutine
   send("Message 2 from producer")
   print("Producer Coroutine finished")
end

function Consumer()
   print("Consumer started")
   local msg = receive() -- receive a message from queue
   print("Consumer received:", msg)
   coroutine.yield()  -- yield the consumer coroutine
   msg = receive()  -- receive a message from queue
   print("Consumer received:", msg)
   print("Consumer Coroutine finished")
end

Create Producer and Consumer Coroutines and start them

-- create producer
producer = coroutine.create(Producer)
-- create consumer
consumer = coroutine.create(Consumer)

-- start producer
coroutine.resume(producer)
-- start consumer
coroutine.resume(consumer)
-- resume producer
coroutine.resume(producer)
-- resume consumer
coroutine.resume(consumer)

Complete Example - Chaining coroutines

main.lua

-- queue as empty table
local queue = {}

-- send message will add a message to the queue
function send(message)
   table.insert(queue, message)
end

-- to receive a message from Queue
function receive()
   -- if queue has message
   if #queue > 0 then
      -- remove first entry and return the same  
      return table.remove(queue, 1)
   end
   -- yield the current coroutine if queue is empty
   return coroutine.yield() 
end

function Producer()
   print("Producer Coroutine started")
   send("Message 1 from producer")
   coroutine.yield() -- yield the producer coroutine
   send("Message 2 from producer")
   print("Producer Coroutine finished")
end

function Consumer()
   print("Consumer started")
   local msg = receive() -- receive a message from queue
   print("Consumer received:", msg)
   coroutine.yield()  -- yield the consumer coroutine
   msg = receive()  -- receive a message from queue
   print("Consumer received:", msg)
   print("Consumer Coroutine finished")
end

-- create producer
producer = coroutine.create(Producer)
-- create consumer
consumer = coroutine.create(Consumer)

-- start producer
coroutine.resume(producer)
-- start consumer
coroutine.resume(consumer)
-- resume producer
coroutine.resume(producer)
-- resume consumer
coroutine.resume(consumer)

Output

When we run the above code, we will get the following output−

Producer Coroutine started
Consumer started
Consumer received:	Message 1 from producer
Producer Coroutine finished
Consumer received:	Message 2 from producer
Consumer Coroutine finished

Explanation

  • Here send() function sends message to the queue.

  • receive() function retrieves message from the queue, yields the coroutine if queue is empty.

  • Producer and Consumer coroutines are communicating via the queue.

Advertisements