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.