Lua - Communication Between Coroutines



Coroutines are collaborative by nature and at one time only one coroutine is active. Lua provides a mechanism to share data between coroutines by coroutine.yield() and coroutine.resume() methods.

When coroutine.yield() is called, current coroutine suspends and arguments passed to coroutine.yield() are available as returned values of subsequent coroutine.resume() calls. This is true in reverse way as well, argument passed to coroutine.resume() call are available as returned value of subsequent coroutine.yield() method call.

Direct Value Passing

In following examples, we're communicating between coroutines via yielding and resuming calls. In this example, we're passing values using yield() method.

main.lua

-- Coroutine - Producer
producer = coroutine.create(function()
  print("Producer: Yield Initial Values")
  coroutine.yield("car", 1)
  print("Producer: Resumed and Produced new Values")
  coroutine.yield("scooty", 2)
  print("Producer: Finished.")
end)

-- Main thread - Consumer
print("Main: Communication started")

-- receive true car 1
local status, item, count = coroutine.resume(producer)
print("Main: Received:", item, "count:", count, "Status:", status) 

-- receive true scooty 2
local status, item, count = coroutine.resume(producer)
print("Main: Received:", item, "count:", count, "Status:", status)

-- receive true
local status, item, count = coroutine.resume(producer)
print("Main: Producer finished. Status:", status)

Output

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

Main: Communication started
Producer: Yield Initial Values
Main: Received:	car	count:	1	Status:	true
Producer: Resumed and Produced new Values
Main: Received:	scooty	count:	2	Status:	true
Producer: Finished.
Main: Producer finished. Status:true

In this example, we're passing values using resume() method.

main.lua

-- Coroutine - Consumer
consumer = coroutine.create(function()
  print("Consumer: Started and Waiting for data...")
  local value1 = coroutine.yield()
  print("Consumer: Data received:", value1)
  local value2 = coroutine.yield()
  print("Consumer: Data received:", value2)
  print("Consumer: Finished.")
end)

-- Main thread
coroutine.resume(consumer) -- Start the consumer

-- resume and send first value
coroutine.resume(consumer, "Car") 
-- Consumer will print Consumer: Data received: Car

-- resume and send other value
coroutine.resume(consumer, "Scooty") 
-- Consumer will print Consumer: Data received: Scooty

Output

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

Consumer: Started and Waiting for data...
Consumer: Data received:	Car
Consumer: Data received:	Scooty
Consumer: Finished.

Using Shared Table

We can use a shared table to communicate between two coroutines using a shared structure like a table as shown below −

main.lua

-- Shared table
shared = { messages = {} }

-- Coroutine - Sender
sender = coroutine.create(function()
  table.insert(shared.messages, "Hello!")
  coroutine.yield()  -- suspend the coroutine
  table.insert(shared.messages, "Welcome to Lua World!")
end)

-- Coroutine - Receiver
receiver = coroutine.create(function()
  while #shared.messages > 0 do
    local message = table.remove(shared.messages, 1) -- remove first entry
    print("Receiver: Received:", message) -- print the received message
    coroutine.yield() -- suspend receiver to get more message from sender coroutine
  end
  print("Receiver: Finished.")
end)

coroutine.resume(sender)
coroutine.resume(receiver)
coroutine.resume(sender)
coroutine.resume(receiver)
coroutine.resume(receiver) 

Output

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

Receiver: Received:	Hello!
Receiver: Received:	Welcome to Lua World!
Receiver: Finished.
Advertisements