boost.coroutine學習筆記

網事已瘋發表於2014-10-27

blog中的文章地址:http://www.godebug.org/index.php/archives/124/

boost.coroutine庫是一個stackfull的coroutine,其實本來對這東西沒啥太大興趣,不過後來發現boost.asio對這玩意有個封裝,而且用起來很爽,比我之前寫文章介紹的那個stackless的coroutine強大太多,再加上好久沒寫部落格了,今天就寫點吧。

不廢話了上程式碼:

#include <iostream>
#include <boost/coroutine/all.hpp>

typedef boost::coroutines::asymmetric_coroutine< void >::pull_type pull_coro_t;
typedef boost::coroutines::asymmetric_coroutine< void >::push_type push_coro_t;


void foo(push_coro_t & sink)
{
    std::cout << "1";
    sink();
    std::cout << "2";
    sink();
    std::cout << "3";
    sink();
    std::cout << "4";
}

int main(int argc, char * argv[])
{
    {
        pull_coro_t source(foo);
        while (source)
        {
            std::cout << "-";
            source();
        }
    }

    std::cout << "\nDone" << std::endl;

    return 0;
}

執行輸出:

1-2-3-4
Done

很好理解,當呼叫source的時候進入foo函式,當在foo中呼叫sink的時候就返回到呼叫source的地方,重複呼叫source會多次進入foo函式,每次從上次呼叫sink的下一句開始執行。這些跟那個stackless的coroutine沒啥太大不同,但是不同的是stackless的coroutine不能在reenter中使用區域性變數,即使加個大括號可以使用區域性變數,再次進入函式的時候變數的值也會丟失,而stackfull的則不會。這就帶來了很大的方便。 不過上面的程式碼中的foo沒有返回值,很多時候我們需要從coroutine中返回東西,假設foo需要返回一個int,這時候程式碼需要改成下面這樣:

#include <iostream>
#include <boost/coroutine/all.hpp>

typedef boost::coroutines::asymmetric_coroutine< int >::pull_type pull_coro_t;
typedef boost::coroutines::asymmetric_coroutine< int >::push_type push_coro_t;


void runit(push_coro_t & sink1)
{
    std::cout << "1" << std::endl;
    sink1(10);
    std::cout << "2" << std::endl;
    sink1(20);
    std::cout << "3" << std::endl;
    sink1(30);
    std::cout << "4" << std::endl;
}

int main(int argc, char * argv[])
{
    {
        pull_coro_t source(runit);
        while (source)
        {
            int ret = source.get();
            std::cout << "ret: " << ret << std::endl;
            source();
        }
    }

    std::cout << "\nDone" << std::endl;

    return 0;
}

執行輸出:

1
ret: 10
2
ret: 20
3
ret: 30
4

Done

太簡單了,不解釋了。。對照沒有返回值的程式碼看看那裡改了就一目瞭然。

不過光有返回值不行,還得有引數:

#include <iostream>
#include <boost/coroutine/all.hpp>

typedef boost::coroutines::asymmetric_coroutine< int >::pull_type pull_coro_t;
typedef boost::coroutines::asymmetric_coroutine< int >::push_type push_coro_t;


void runit(pull_coro_t & source)
{
    std::cout << source.get();
    source();
    std::cout << source.get();
    source();
    std::cout << source.get();
    source();
    std::cout << source.get();
}

int main(int argc, char * argv[])
{
    {
        push_coro_t sink(runit);

        int i = 0;
        while (sink)
        {
            ++i;
            sink(i);
            std::cout << "-";
        }
    }

    std::cout << "\nDone" << std::endl;

    return 0;
}

執行輸出:

1-2-3-4- Done

其實就是把pull和push給對調了一下,把引數push給被呼叫的函式,不過好像沒法同時傳多個引數,也不能同時有引數和返回值(至少我在他的example中沒找到,有知道的希望能不吝賜教),應該可以用tuple和返回引數解決,不想測試了。pull和push除了一個是接收引數一個是返回之外,還有點差別,pull在構造的時候就會呼叫傳遞給他的函式,push不會,判斷呼叫都完成了沒有也有一定的差別。不過懶得管他了反正最後要用的是asio封裝的coroutine,這個只是瞭解一下

本來還打算看看這個coroutine咋實現的,結果發現他是自己用匯編實現了底層細節,自己從FS暫存器中讀取了執行緒環境塊(TEB)和SEH鏈神馬的處理了,然後就是記錄呼叫push和pull函式的地址,以及各種jmp跳轉往返於push和pull之間。有點略複雜,就沒詳細看。

over