2.11 - Подпрограммы
Lua поддерживает подпрограммы, эту технологию часто называют общей многопоточностью.
Подпрограмма Lua
представляет собой независимый поток выполнения. Несмотря на это, в отличие от
потоков в традиционных многопоточных системах, подпрограмма может приостановить
свое выполнение только в результате явного вызова функции yield.
Подпрограммы создаются вызовом coroutine.create. Единственным аргументом является имя главной функции подпрограммы. Функция create только создает новую подпрограмму и возвращает указатель на нее (объект типа thread), запуск подпрограммы не выполняется.
При вызове функции coroutine.resume
и передаче ей в качестве первого аргумента результата вызова coroutine.create,
процедура запускается на выполнение с первого оператора ее главной функции. Остальные
параметры из вызова coroutine.resume
передаются в основную функцию подпрограммы. После запуска подпрограмма выполняется
до завершения либо до вызова yields.
Подпрограмма останавливается только в двух случаях: нормально, когда осуществляется
возврат (явно или неявно) из главной функции; или аварийно в случае
необработанной ошибки. При нормальном завершении coroutine.resume
возвращает true плюс любые
значения, возвращаемые из основной функции подпрограммы. В случае
ошибок, coroutine.resume
вернет значение false плюс сообщение об ошибке.
Для приостановки выполнения попрограммы используется функция coroutine.yield.
При вызове yields соответствующий coroutine.resume
возвращает управление немедленно, точно так же, как если бы вызов yield произошел
во вложенном вызове функции (т.е. не в главной функции, а в функции, вызванной
непосредственно или опосредованно из нее). При вызове yield функция coroutine.resume
также возвращает true плюс все входные параметры, переданные в coroutine.yield.
В следующий раз, когда подпрограмма продолжит работу, ее выполнение начнется с
оператора, следующего за yield, соответственно из coroutine.yield
вернутся параметры, переданные в coroutine.resume.
Функция coroutine.wrap
создает подпрограмму и осуществляет ее запуск. Параметры, переданные в нее в
качестве дополнительных аргуметров, попадают в неявный вызов coroutine.resume.
Вызов coroutine.wrap
возвращает те же значения, что и coroutine.resume,
за исключением первого (булевского кода ошибки). В отличие от coroutine.resume,
coroutine.wrap
не перехватывает ошибки – все ошибки попадают на уровень вызывающей функции.
Рассмотрим в качестве примера следующий код:
function foo (a)
print("foo", a)
return coroutine.yield(2*a)
end
co = coroutine.create(function (a,b)
print("co-body", a, b)
local r = foo(a+1)
print("co-body", r)
local r, s = coroutine.yield(a+b, a-b)
print("co-body", r, s)
return b, "end"
end)
print("main", coroutine.resume(co, 1, 10))
print("main", coroutine.resume(co, "r"))
print("main", coroutine.resume(co, "x", "y"))
print("main", coroutine.resume(co, "x", "y"))
При запуске на экран выведется:
co-body 1 10
foo 2
main true 4
co-body r
main true 11 -9
co-body x y
main true 10 end
main false cannot resume dead coroutine
|