« お気軽にXMLを扱ってみる 其の7 | トップページ | boost.contextを使ってみました。 »

2011年4月10日 (日)

コルーチン

setjmp / longjmp関数を使用したコルーチンをネットで調べ、自分が使いやすいように整形。

setjmp / longjmp関数はC++のオブジェクトに対応していないみたいですね。
まぁ、コルーチン化したい部分には、C++オブジェクトは置かないように注意すればいいかな。

コルーチンクラス

/* ----------------------------------------------------------------------------
 *  coroutine.hpp : コルーチン
 * ---------------------------------------------------------------------------- */
#pragma once

#define NOINLINE __declspec( noinline )

#include <setjmp.h>

namespace D1Z {
    class CCoroutine {
        enum {
            STKPAD = 1<<16,
            STKSAV = 1<<10
        };
    public:
        enum ERoutineState {
            rsSTART,        // 初期状態
            rsCONTINUE,      // 継続
            rsEND,      // 終了
        };
    public:
        /* 呼び出し */
        ERoutineState call( void ) {
            if( setjmp( m_PointA ) == 0 ) {
                if( m_state != rsSTART ) {
                    memcpy( const_cast<char*>( m_stkptrL ), m_Stack, m_stkptrH - m_stkptrL );
                    longjmp( m_PointB, 1 );
                }
                callDoProcess();
            }
            return m_state;
        }
    public:
        /* コンストラクタ */
        CCoroutine() : m_state( rsSTART ) { ; }
        /* デストラクタ */
        virtual ~CCoroutine() { ; }

    protected:
        /* 処理 */
        virtual void doProcess( void ) = 0;

    protected:
        /* 処理の呼び出し */
        NOINLINE void callDoProcess( void ) {
            char stktmp[STKPAD];
            m_stkptrH = stktmp;
            doProcess();
        }
        /* 制御を渡す */
        NOINLINE void yield( ERoutineState value ) {
            char curtmp;
            m_stkptrL = ( &curtmp ) - 16;
            if( setjmp( m_PointB ) == 0 ) {
                m_state = value;
                memcpy( m_Stack, const_cast<char*>( m_stkptrL ), m_stkptrH - m_stkptrL );
                longjmp( m_PointA, 1 );
            }
        }
    protected:
        CCoroutine( const CCoroutine& );
        CCoroutine& operator=( const CCoroutine& );

    protected:
        volatile ERoutineState m_state;
        volatile char*         m_stkptrH;
        volatile char*         m_stkptrL;
        jmp_buf                m_PointA;
        jmp_buf                m_PointB;
        char                   m_Stack[STKSAV];
    };
} // D1Z

使用サンプル

/* ----------------------------------------------------------------------------
 *  coroutine.cpp : コルーチン
 * ---------------------------------------------------------------------------- */
#include <iostream>
#include "coroutine.hpp"

using namespace std;

class CTest : public D1Z::CCoroutine {
protected:
    void doProcess( void ) {
        for( int n=0; n<10; ++n ) {
            yield( rsCONTINUE );
            cout << n << endl;
        }
        yield( rsEND );
    }
};

int main( int argc, char** argv ) {
    CTest test;
    D1Z::CCoroutine::ERoutineState state = D1Z::CCoroutine::rsSTART;
    while( state != D1Z::CCoroutine::rsEND ) {
        state = test.call();
        cout << "back!!" << endl;
    }
    return 0;
}

|

« お気軽にXMLを扱ってみる 其の7 | トップページ | boost.contextを使ってみました。 »

C++」カテゴリの記事

コメント

コメントを書く



(ウェブ上には掲載しません)




トラックバック


この記事へのトラックバック一覧です: コルーチン:

« お気軽にXMLを扱ってみる 其の7 | トップページ | boost.contextを使ってみました。 »