文章轉自: http://blog.csdn.net/wusheng520/article/details/7954666html
1、基本環境:函數
Microsoft Windows XP/Service Pack 2
lua
Lua 5.1.4 Copyright (C) 1994-2008 Lua.org, PUC-Riospa
2、 coroutine的接口:.net
(1) coroutine.create()線程
(2) coroutine.resume()code
(3) coroutine.yield()orm
(4) coroutine.status()htm
(5) coroutine.wrap()
blog
(6) coroutine.running()
3、coroutine的狀態分爲suspend, running, dead三種。
4、coroutine的基本流程
下面的代碼說明了coroutine的基本流程
co = coroutine.create(function(a, b) print(coroutine.status(co), "start") --執行代碼,coroutine狀態爲running--->(3) print("co", a, b) print(coroutine.status(co), "end") --執行代碼,coroutine狀態爲running --->(4) end) print(coroutine.status(co)) --剛建立的coroutine的狀態爲suspend --->(1) coroutine.resume(co, 1, 2) --啓動coroutine,將跳轉到coroutine的function執行 --->(2) print(coroutine.status(co)) --coroutine執行完畢,狀態爲dead --->(5)
代碼的執行結果以下:
>lua -e "io.stdout:setvbuf 'no'" "cur.lua" suspended running start co 1 2 running end dead >Exit code: 0
5、yield對coroutine流程的干預
若是沒有yield,coroutine的生老病死就是上面這樣一個流程了。
接下來輪到yield出場,它的做用是將一個running的coroutine掛起,相應的其狀態就會被切換成suspend。
先貼代碼,再解釋
co = coroutine.create(function(a, b) print(coroutine.status(co), "start") --->(2) for i = 1, 10 do print("co", a, b) --->(3)(6) coroutine.yield() print(coroutine.status(co), "after yield") --->(5) end print(coroutine.status(co), "end") end) print(coroutine.status(co)) --->(1) coroutine.resume(co, 1, 2) print(coroutine.status(co)) --->(4) coroutine.resume(co, 1, 2) print(coroutine.status(co)) --->(7)
執行結果貼一下:
>lua -e "io.stdout:setvbuf 'no'" "cur.lua" suspended running start co 1 2 suspended running after yield co 1 2 suspended >Exit code: 0
在執行到yield以後,代碼跳轉到上一次resume代碼的後一條代碼執行
再次調用resume,代碼就跳轉到上一次yield代碼的後一條代碼執行。
通常來講,resume方法在主線程中調用;而yield則是在coroutine內調用,包括coroutine內部調用的函數內部。
固然了,在coroutine中調用resume沒有什麼問題,但這樣是沒有什麼意義的,由於若是代碼還在coroutine中執行的話,則說明其狀態必定是running的,這個時候的resume是沒有任何意義的。而在主線程中調用yield,會致使 「lua: attempt to yield across metamethod/C-call boundary」的錯誤。
6、resume, function()以及yield之間的參數傳遞和返回值傳遞
co1 = coroutine.create(function(a, b) print("co", a, b) end) co2 = coroutine.create(function(a, b) print("co", a, b) end) co3 = coroutine.create(function(a, b) print("co", a, b) end) coroutine.resume(co1, 1) coroutine.resume(co2, 1, 2) coroutine.resume(co3, 1, 2, 3)
執行結果以下:
>lua -e "io.stdout:setvbuf 'no'" "cur.lua" co 1 nil co 1 2 co 1 2 >Exit code: 0
這個說明resume的參數除了coroutine句柄(第一個參數)之外,都傳遞給了function,關係跟表達式賦值是一致的,少的以nil補足,多的捨棄。
若是在coroutine中包含有yield,狀況會複雜一些。咱們進一步挖掘coroutine的流程:
1 resume
2 function
3 yield
4 yield掛起,第一次 resume返回
5 第二次resume
6 yield返回
7 function 繼續執行
在這個流程的第一步的時候,resume的參數會傳遞給function,做爲參數(具體如上);到了第三步的時候,yield的參數會做爲resume返回值的一部分;而第二次resume(第五步)的時候,resume的參數的做用發生了改變,resume的參數會傳遞給yield,作爲yield的返回值。
這個過程很精巧,在coroutine執行的過程當中返回,必然須要告訴外部如今coroutine這個時候的內部的的狀況,經過惟一的接口yield的參數做爲resume的返回值,高;到了第二次resume的時候,外部的環境必然發生了改變, 怎麼通知coroutine內部呢,一樣的想法,將惟一的接口resume的參數經過yield的返回的途徑返回到coroutine內部,同樣的高明。
貼一個引用的代碼,代碼源出處見參考:
function foo (a) print("foo", a) -- foo 2 return coroutine.yield(2 * a) -- return: a , b end co = coroutine.create(function (a , b) print("co-body", a, b) -- co-body 1 10 local r = foo(a + 1) print("co-body2", r) local r, s = coroutine.yield(a + b, a - b) print("co-body3", r, s) return b, "end" end) print("main", coroutine.resume(co, 1, 10)) -- true, 4 print("------") print("main", coroutine.resume(co, "r")) -- true 11 -9 print("------") print("main", coroutine.resume(co, "x", "y")) -- true 10 end print("------") print("main", coroutine.resume(co, "x", "y")) -- false cannot resume dead coroutine print("------")
結果以下:
>lua -e "io.stdout:setvbuf 'no'" "cur.lua" co-body 1 10 foo 2 main true 4 ------ co-body2 r main true 11 -9 ------ co-body3 x y main true 10 end ------ main false cannot resume dead coroutine ------ >Exit code: 0
剛看有點繞,你們靜心看看, 必有收穫,畢竟代碼不長。
參考:
1 programming in Programming in Lua
2 lua-5.1中文手冊
3 http://www.cnblogs.com/yjf512/archive/2012/05/28/2521412.html