Lua coroutine

Posted by gasoga on Wed, 02 Mar 2022 10:24:58 +0100

Reprinted from: Lua coroutine | rookie tutorial Lua coroutine what is coroutine? Lua coroutine is similar to thread: it has independent stack, independent local variables, independent instruction pointers, and shares global variables and most other things with other coroutines. Collaboration is a very powerful function, but it is also very complex to use. The main difference between thread and cooperative program is that a program with multiple threads can run several threads at the same time, while cooperative programs need to cooperate with each other. Only one collaboration program is running at any given timehttps://www.runoob.com/lua/lua-coroutine.html

 

What is coroutine?

Lua coroutine is similar to thread: it has independent stack, independent local variables, independent instruction pointers, and shares global variables and most other things with other coroutines.

Collaboration is a very powerful function, but it is also very complex to use.

Difference between thread and cooperative program

The main difference between threads and cooperative programs is that a program with multiple threads can run several threads at the same time, while cooperative programs need to cooperate with each other.

Only one cooperative program is running at any given time, and the running cooperative program will be suspended only when it is explicitly required to suspend.

Cooperative programs are somewhat similar to synchronous multithreading, and several threads waiting for the same thread lock are somewhat similar to cooperation.

Basic grammar

methoddescribe
coroutine.create()Create coroutine and return coroutine. The parameter is a function that wakes up the function call when used with resume
coroutine.resume()Restart coroutine and use it with create
coroutine.yield()Suspend coroutine and set coroutine to the suspended state. This can have many useful effects in combination with resume
coroutine.status()View the status of coroutine
Note: there are three statuses of coroutine: dead, suspended and running. Please refer to the following procedure for specific time
coroutine.wrap()Create coroutine and return a function. Once you call this function, you will enter coroutine, which is repeated with the create function
coroutine.running()Return the running coroutine. A coroutine is a thread. When running is used, it returns a corouting thread number

The following example demonstrates the usage of each of the above methods:

coroutine_test.lua file

-- coroutine_test.lua file
co = coroutine.create(
    function(i)
        print(i);
    end
)
 
coroutine.resume(co, 1)   -- 1
print(coroutine.status(co))  -- dead
 
print("----------")
 
co = coroutine.wrap(
    function(i)
        print(i);
    end
)
 
co(1)
 
print("----------")
 
co2 = coroutine.create(
    function()
        for i=1,10 do
            print(i)
            if i == 3 then
                print(coroutine.status(co2))  --running
                print(coroutine.running()) --thread:XXXXXX
            end
            coroutine.yield()
        end
    end
)
 
coroutine.resume(co2) --1
coroutine.resume(co2) --2
coroutine.resume(co2) --3
 
print(coroutine.status(co2))   -- suspended
print(coroutine.running())
 
print("----------")

The execution output of the above example is:

1
dead
----------
1
----------
1
2
3
running
thread: 0x7fb801c05868    false
suspended
thread: 0x7fb801c04c88    true
----------

coroutine.running shows that the underlying implementation of coroutine is a thread.

When creating a coroutine, an event is registered in the new thread.

When the event is triggered by resume, the coroutine function of create is executed. When yield is encountered, it means suspending the current thread and waiting for the event to be triggered by resume again.

Next, let's analyze a more detailed example:

example

function foo (a)
    print("foo Function output", a)
    return coroutine.yield(2 * a) -- return  2*a Value of
end
 
co = coroutine.create(function (a , b)
    print("First collaborative program execution output", a, b) -- co-body 1 10
    local r = foo(a + 1)
     
    print("Second collaborative program execution output", r)
    local r, s = coroutine.yield(a + b, a - b)  -- a,b The value of is passed in when the collaborator is called for the first time
     
    print("The third collaborative program execution output", r, s)
    return b, "End collaboration program"                   -- b The value of is passed in the second call to the collaborator
end)
       
print("main", coroutine.resume(co, 1, 10)) -- true, 4
print("--Split line----")
print("main", coroutine.resume(co, "r")) -- true 11 -9
print("---Split line---")
print("main", coroutine.resume(co, "x", "y")) -- true 10 end
print("---Split line---")
print("main", coroutine.resume(co, "x", "y")) -- cannot resume dead coroutine
print("---Split line---")

The execution output of the above example is:

Output of the first collaborative program execution 1 # 10
 foo function output {2
main    true    4
 --Split line----
The second collaborative program execution output # r
main    true    11    -9
 ---Split line---
The third collaborative program execution output # x # y
 main true 10 end collaboration program
 ---Split line---
main    false    cannot resume dead coroutine
 ---Split line---

The above examples are as follows:

  • Call resume to wake up the cooperative program. If the resume operation is successful, return true; otherwise, return false;
  • Collaborative program operation;
  • Run to yield statement;
  • Yield suspends the collaboration program and returns the first resume; (Note: yield returns here, and the parameter is the parameter of resume)
  • The second resume wakes up the collaboration program again; (Note: among the parameters of resume here, except the first parameter, the remaining parameters will be used as the parameters of yield)
  • yield return;
  • The collaborative program continues to run;
  • If you continue to call the resume method after the cooperative program continues to run, the output is: cannot resume dead coroutine

The strong cooperation between resume and yield is that resume is in the main process, which transfers the external state (data) into the collaborative program; Yield returns the internal status (data) to the main process.

Producer consumer problem

Now I will use Lua's collaborative program to complete the classic problem of producer consumer.

example

local newProductor

function productor()
     local i = 0
     while true do
          i = i + 1
          send(i)     -- Send produced goods to consumers
     end
end

function consumer()
     while true do
          local i = receive()     -- Get goods from producers
          print(i)
     end
end

function receive()
     local status, value = coroutine.resume(newProductor)
     return value
end

function send(x)
     coroutine.yield(x)     -- x Indicates the value to be sent. After the value is returned, the collaboration program will be suspended
end

-- Start program
newProductor = coroutine.create(productor)
consumer()

The execution output of the above example is:

1
2
3
4
5
6
7
8
9
10
11
12
13
......

Topics: lua