local Queue = {} function Queue:push(x) if self.max_size > 0 and #self.elements >= self.max_size then error("queue is full", 2) end table.insert(self.elements, x) end function Queue:pop(x) if #self.elements == 0 then error("queue is empty", 2) end return table.remove(self.elements, 1) end function Queue:len() return #self.elements end function Queue:is_empty() return #self.elements == 0 end function Queue:is_full() return #self.elements >= self.max_size end function Queue:new(max_size) return setmetatable({ max_size = max_size or -1, elements = {}, }, { __index = Queue, __metatable = "permission denied", }) end local Consumer = {} function Consumer.consume(self, stop) local consumed = 0 while stop == false do if consumed >= self.n then print(string.format("Consumer: aleady consumed %d element(s). yielding...", consumed)) _, stop = coroutine.yield() print(string.format("Consumer: awoken from consumed, stop is %s.", stop)) consumed = 0 else if self.queue:is_empty() then print(string.format("Consumer: queue is empty. yielding...")) _, stop = coroutine.yield() print(string.format("Consumer: awoken from queue empty, stop is %s.", stop)) consumed = 0 else local x = self.queue:pop() print(string.format("Consumer: consumed %s", x)) consumed = consumed + 1 end end end while not self.queue:is_empty() do local x = self.queue:pop() print(string.format("Consumer[stop=%s]: consumed %s", stop, x)) end print(string.format("Consumer: exit")) end function Consumer:new(queue, n) if queue == nil then error("no queue provied", 2) end return setmetatable({ queue = queue, n = n or 1, }, { __index = self, __metatable = "permission denied", } ) end local Producer = {} function Producer.produce(self, stop) local produced = 0 local x = 1 while stop == false do if produced >= self.n then print(string.format("Producer: already produced %d element(s). yielding...", produced)) _, stop = coroutine.yield() print(string.format("Producer: awoken from produced. stop is %s.", stop)) produced = 0 else if self.queue:is_full() then print(string.format("Producer: queue is full. yielding...")) _, stop = coroutine.yield() print(string.format("Producer: awoken from queue full. stop is %s.", stop)) produced = 0 else print(string.format("Producer: produced %s", x)) self.queue:push(x) x = x + 1 produced = produced + 1 end end end print(string.format("Producer: exit")) return true end function Producer:new(queue, n) if queue == nil then error("no queue provied", 2) end return setmetatable({ queue = queue, n = n or 1, }, { __index = self, __metatable = "permission denied", } ) end function main() local max_loop = 3 local stop = false local queue = Queue:new(6) local consumer = Consumer:new(queue, 2) local producer = Producer:new(queue, 4) local consumer_thread = coroutine.create(consumer.consume) local producer_thread = coroutine.create(producer.produce) local consumer_status = coroutine.status(consumer_thread) local producer_status = coroutine.status(producer_thread) local loop_cnt = 1 while consumer_status ~= "dead" or producer_status ~= "dead" do if loop_cnt > max_loop then stop = true end if consumer_status ~= "dead" then print(string.format("Main: resuming consumer with stop %s", stop)) local status, err = coroutine.resume(consumer_thread, consumer, stop) if not status then error(string.format("failed to consume, err: %s", err), 2) end end if producer_status ~= "dead" then print(string.format("Main: resuming producer with stop %s", stop)) local status, err = coroutine.resume(producer_thread, producer, stop) if not status then error(string.format("failed to produce, err: %s", err), 2) end end consumer_status = coroutine.status(consumer_thread) producer_status = coroutine.status(producer_thread) print(string.format("Main: consumer status is %s, producer status is %s", consumer_status, producer_status)) loop_cnt = loop_cnt + 1 end end main()