文檔地址
http://www.boost.org/doc/libs/1_60_0/doc/html/boost_asio/reference/coroutine.html
文檔翻譯
協程
提供實現不需要棧的協程的支持
class coroutine
成員函數
函數名 |
描述 |
coroutine |
構造成為初始化狀態 |
is_child |
如果是一個fork子協程的話返回true |
is_complete |
如果到了終止狀態就返回true |
is_parent |
如果是fork的父協程的話返回true |
coroutine
類可以用來實現無棧的協程。這個類自身被用來保存協程的狀態。
coroutine
類可以支持復制構造和賦值。最大一個int的空間占用??梢援斪骰愂褂?/p>
class session : coroutine
{
// 。。。
};
或者作為一個數據項。
class session
{
//。。。
coroutine coro_;
};
或者設置作為一個lambda或者bind()
的參數。 這種實現的重點是在協程存在的時候,這個對下必須不被釋放。
偽關鍵字
協程是聯合特定偽關鍵子使用的,這些偽關鍵字使用宏實現。這些宏被定義在
#include <boost/asio/yield.hpp>
可以通過下面的頭文件方便的undefine
#include <boost/asio/unyield.hpp>
reenter
reenter
宏是用來定義一段協程的。他僅僅接收1個參數 : 一個coroutine
的指針或者引用。比如 , 如果基類是coroutine
你可以這樣寫 :
reenter (this)
{
}
如果coroutine
是成員變量的話
reenter (coro_)
{
}
當一段reenter
代碼被執行的時候,直接跳轉到最近的一次yeild
或者fork
位置后執行。
協程代碼段也可以是一個單獨的語句
reenter (this) for (;;)
{
}
局限性: 由于reenter
宏是用swtich來實現的,所以你在協程代碼中定義局部變量的時候必須格外注意。 這個變量不能定義在重入的時候會被跳過的地方。
yield 語句
這種格式的 yield
關鍵字通常被用來做異步操作 :
yield socket_->async_read_some(buffer(*buffer_), *this);
這個分成4步驟實現:
- yield 保存當前協程的狀態.
- 初始化異步操作。
- 繼續執行點被設置為下一行。
- 控制跳轉到協程末尾,推出協程.。
當異步操作完成后,再次執行這個協程。重入后從繼續執行點執行。記住,異步操作執行后再次調用協程是很重要的。
1 yield
2 {
3 mutable_buffers_1 b = buffer(*buffer_);
4 socket_->async_read_some(b, *this);
5 }
yield return expression ;
這種形式通常被用來做基于協程的解析器。比如 :
1 struct interleave : coroutine
2 {
3 istream& is1;
4 istream& is2;
5 char operator()(char c)
6 {
7 reenter (this) for (;;)
8 {
9 yield return is1.get();
10 yield return is2.get();
11 }
12 }
13 };
定義了一個小協程來間隔的從兩個流中讀取數據,
這個分成3步驟實現
- yield 保存當前協程的狀態.
- 繼續執行點被設置為下一行。
- 函數返回表達式的值
yield ;
This form of yield is equivalent to the following steps:
這個分成3步驟實現
- yield 保存當前協程的狀態.
- 繼續執行點被設置為緊跟著分號。
- 控制函數到達代碼末尾。
這種格式在協程被用來組織線程的合作和調度的時候。比如 :
1 struct task : coroutine
2 {
3 //。。。
4 void operator()()
5 {
6 reenter (this)
7 {
8 while (
not finished
)
9 {
10
do something 
11 yield;
12
do some more 
13 yield;
14 }
15 }
16 }
17 //。。。
18 };
19 //。。。
20 task t1, t2;
21 for (;;)
22 {
23 t1();
24 t2();
25 }
yield break ;
最后一種格式是用來顯示的終止協程。分成兩步驟:
yeild
將協程狀態設置為終止。 - 控制函數到達代碼末尾。
一旦協程終止。調用 is_complete()
返回true
。 協程不能再被重入。
注意 : 當協程代碼塊被顯示終止的時候,比如return , 拋出異?;蛘哌\行到結尾的時候,都會被設置為終止。
fork statement
fork
偽關鍵字是用來使得一個協程分支的。它將一個協程分成兩個(或者更多)復制。一個使用場景是在服務器,產生一個新的協程來處理每個客戶端的鏈接。
1 reenter (this)
2 {
3 do
4 {
5 socket_.reset(new tcp::socket(io_service_));
6 yield acceptor->async_accept(*socket_, *this);
7 fork server(*this)();
8 } while (is_parent());
9 // client-specific handling follows
10 }
這個分4個步驟實現 :
fork
保存當前的協程狀態. - 創建一個協程的復制,要么立刻執行它,要么呆會。
- 回復點緊跟著分號之后.
- 對于父類,回復點在下一行。
函數is_parenet()
和is_child()
可以被用來區分父協程和自協程。你可以用他們來改變后面的工作順序。
注意: fork
關鍵字并不真的實現分支。是程序來創建一個新的副本并調用它。你可以像上面那樣立刻執行,也可以利用類似io_server::post()
這樣的接口來延遲執行。
替代的宏
BOOST_ASIO_CORO_REENTER
instead of reenter
BOOST_ASIO_CORO_YIELD
instead ofyield
BOOST_ASIO_CORO_FORK
instead of fork
源碼解析
來源 :
boost/asio/coroutine.hpp
1 // 定義 coroutine 類, 本質上是一個行號記錄類。
2 // 行號是這個東西沖入的唯一依據。
3 class coroutine
4 {
5 public:
6 // 初始化0
7 /// Constructs a coroutine in its initial state.
8 coroutine() : value_(0) {}
9
10 // fork 的子協程初始行號是當前行號的負數。因此判斷它是否為負數。
11 // 當子協程支持再fork后,value_變成新的行號,便不再被認為是child。
12 /// Returns true if the coroutine is the child of a fork.
13 bool is_child() const { return value_ < 0; }
14 // 返回 ! is_child()
15 /// Returns true if the coroutine is the parent of a fork.
16 bool is_parent() const { return !is_child(); }
17
18 // 當reenter宏包被的模塊(里面應該有yeild或者fork , 否則這個模塊僅僅是普通的代碼塊,永遠不存在結束狀態)執行結束的時候,vaule_被設置為-1。
19 /// Returns true if the coroutine has reached its terminal state.
20 bool is_complete() const { return value_ == -1; }
21
22 private:
23 friend class detail::coroutine_ref;
24 int value_;
25 };
26
27
28 namespace detail {
29 // 引用類,使用這個類來方便的修改& 檢測coroutine 類的值。
30 class coroutine_ref
31 {
32 public:
33 coroutine_ref(coroutine& c) : value_(c.value_), modified_(false) {}
34 coroutine_ref(coroutine* c) : value_(c->value_), modified_(false) {}
35 ~coroutine_ref() { if (!modified_) value_ = -1; }
36 operator int() const { return value_; }
37 int& operator=(int v) { modified_ = true; return value_ = v; }
38 private:
39 void operator=(const coroutine_ref&);
40 int& value_;
41 bool modified_;
42 };
43
44 } // namespace detail
45 } // namespace asio
46 } // namespace boost
47
48 #define BOOST_ASIO_CORO_REENTER(c) \
49 switch (::boost::asio::detail::coroutine_ref _coro_value = c)\
50 case -1: if (_coro_value) \
51 { \
52 goto terminate_coroutine; \
53 terminate_coroutine: /*這是標記reenter模塊結束的清理代碼*/\
54 _coro_value = -1; \
55 goto bail_out_of_coroutine; /*退出這次執行*/\
56 bail_out_of_coroutine: \
57 break; \
58 } \
59 else case 0: /*下面是我們的代碼塊*/
60
61 #define BOOST_ASIO_CORO_YIELD_IMPL(n) \
62 for (_coro_value = (n);;) \
63 if (_coro_value == 0) \
64 { \
65 case (n): /*當reenter模塊被重入的時候,根據行號直接跳轉到這里從而直接執行下一行*/; \
66 break; \
67 } \
68 else /*第一次執行到這里*/\
69 switch (_coro_value ? 0 : 1) \
70 for (;;) \
71 case -1: if (_coro_value)/*執行yeild break 終止 */ \
72 goto terminate_coroutine; \
73 else for (;;)/*執行yeild 而不是 yeild return 的話,循環 */\
74 case 1: if (_coro_value) \
75 goto bail_out_of_coroutine; \
76 else case 0:
77
78 #define BOOST_ASIO_CORO_FORK_IMPL(n) \
79 for (_coro_value = -(n);; _coro_value = (n))/*這個循環其實僅僅執行兩次 : core_calue == -n 執行子協程和 core_value == n 執行父協程*/ \
80 if (_coro_value == (n)) \
81 { \
82 case -(n): ; \
83 break; \
84 } \
85 else
86
87 #if defined(_MSC_VER)
88 # define BOOST_ASIO_CORO_YIELD BOOST_ASIO_CORO_YIELD_IMPL(__COUNTER__ + 1)
89 # define BOOST_ASIO_CORO_FORK BOOST_ASIO_CORO_FORK_IMPL(__COUNTER__ + 1)
90 #else // defined(_MSC_VER)
91 # define BOOST_ASIO_CORO_YIELD BOOST_ASIO_CORO_YIELD_IMPL(__LINE__)
92 # define BOOST_ASIO_CORO_FORK BOOST_ASIO_CORO_FORK_IMPL(__LINE__)
93 #endif // defined(_MSC_VER)
94
95 #endif // BOOST_ASIO_COROUTINE_HPP
96