zoukankan      html  css  js  c++  java
  • 四、Lua协同程序

    一、协同程序基础

      1.什么是协同程序

      协同程序与线程差不多,也就是一条执行序列,拥有自己独立的栈、局部变量和指令指针(即可以保存变量的值和状态),同时又与其他协同程序共享全局变量和其他大部分东西。

      与线程的区别是具有多个线程的程序可以同时运行几个线程,而程序任意时刻只能运行一个协同程序,并且协同程序只有被显示地(执行挂起函数)要求挂起才会暂停。

      2.四种状态

      (1)挂起(suspended):创建时或执行了操作coroutine.yield()

      (2)运行(running):执行了coroutine.resume()

      (3)死亡(dead):最后一次调用resume时,协同程序的内容已执行完毕,并且已经返回。resume状态为dead的协同程序将返回false及错误消息,不再执行主函数体。

      (4)正常(normal):当一个协同程序A唤醒另一个协同程序B时,A就处于一种特殊状态——既不是挂机状态(A不能继续执行),也不是运行状态(B在运行)。

      3.相关函数(都存放在全局table coroutine中)

      (1)create(fun):用于创建协同程序,只有一个参数,就是一个函数(一般为匿名函数),函数中的代码就是协同程序将要执行的内容。create返回值的类型为thread。创建后的协同程序处于挂起状态。

      (2)resume(co,...):启动或再次启动协同程序。参数列表中:co表示将要被启动的协同程序,后面为变长的可选参数。

      (3)yield(...):使正在运行的协同程序挂起,之后可以再恢复运行(调用resume)。只能被协同程序的主函数调用(即在协同程序执行的内容中调用)。参数列表为可选的变长参数。

      (4)status(co):检查协同程序的当前状态,返回值为四中状态中的一种。参数co为待检查的协同程序。

      4.有用机制:通过一对resume-yield交换数据

      原理:

      (1)所有传递给resume的额外参数(...)都将视为协同程序主函数的参数。如:

              co = coroutine.create ( function(a,b)  print("co:",a,b)  end )  --创建协同程序

              coroutine.resume(co,10,20)  --> co:10  20  --启动协同程序,其中10,20就是额外参数,传递给了协同程序的主函数(匿名函数)

      (2)resume的返回值中包含传递给yield的所有参数。如:

                   co = coroutine.create( function(a,b)

                  coroutine.yield(a+b,a-b)  --在协同程序的主函数中直接调用yield

                  i = i+1  --有语法错误

                end )          

              第一次调用resume:print(coroutine.resume(co,20,10)) -->true  30  10   --第一个返回值为true表示协同程序执行完毕或执行到yield之前没有发生错误,后面的返回值就是传递给yield的参数。   

              第二次调用resume:print(coroutine.resume(co,20,10)) -->false,attempt to perform arithmetic on global 'i' (a nil value) --resume 第一个返回值为true并不能说明协同程序没有错误。

      (3)yield的返回值就是对应resume传入的额外参数。如:

              co = coroutine.create( function() print("co:",coroutine.yield()) end)

              coroutine.resume(co) -->   --resume中没有额外参数,则yield不会返回值,协同程序挂起

      (4)当协同程序结束时,它的主函数返回的值都将作为resume的返回值。如:

              co = coroutine.create( function() return 1,2 end )

              print(coroutine.resume(co)) -->true 1  2 

    二、协同程序的应用

      1.生产者-消费者

      (1)生产者-消费者一般程序表示:

          function producer() --生产者                                    function consumer() --消费者

            while true do                     while true do   

              local x = io.read()                  local x = receive()

              send(x)                       io.write(x," ")

            end                           end 

          end                          end 

          问题关键:如何将send和receive匹配起来?

      (2)生产者-消费者协同程序实现   

          function send(x) --协同程序主函数中被调用,因而可以调用yield
            coroutine.yield(x) --参数x将作为resume的返回值
          end

          producer = coroutine.create( function()  --在这里可以理解为生产者
                while true do
                  local x = io.read() --输入,这里可理解为生产的东西
                  send(x)
                end
              end)

          function receive()  --在这里可以理解为消费者
            local status, value = coroutine.resume(producer) --启动协同程序
            return value
          end

          程序通过调用消费者receive()来唤醒生产者(即协同程序),然后通过将“生产的”内容x作为参数传递给yield,最后作为resume的返回值,赋给value(即消费者得到生产者生产的东西)

          实质上利用了一对resume-yield交换数据。

  • 相关阅读:
    deepin linux手工更新系统
    redis使用redis-cli查看所有的keys及清空所有的数据
    使用浏览器地址栏调用CXF Webservice的写法
    windows 80端口被占用
    How to install 64-bit Google Chrome 28+ on 64-bit RHEL/CentOS 6 or 7
    CAS 单点登录流程
    Restful是什么,SOAP Webservice和RESTful Webservice
    SpringMVC中的@PathVariable
    VMWare安装苹果操作系统OS X
    eclipse(adt-bundle)的Android SDK Manager下载不了谷歌的东西怎么办?
  • 原文地址:https://www.cnblogs.com/heyongqi/p/5170031.html
Copyright © 2011-2022 走看看