SlideShare a Scribd company logo
Boost.Contextで継続


                 高橋 晶(Akira Takahashi)
         id:faith_and_brave/@cpp_akira

     2012/04/08(土) Boost.Contextオンリーイベント
Boost.Context
• Oliver Kowalkeが作ったBoost.Fiberというライブラリの、コンテ
  キストスイッチ部分を切り出したライブラリ
• Boost 1.49.0時点でtrunkに入ってる
• 継続(continuation)、ファイバー(fiber)、コルーチン(coroutine)、
  マイクロスレッド(microthread)などなど、いろんな呼び名のあ
  る技術を実現することができる。
資料などのあるところ

• Boost.Context について調べた – melpon日記
  http://d.hatena.ne.jp/melpon/20111213/1323704464
• ドキュメント
  http://ok73.ok.funpic.de/boost/libs/context/doc/html/
• ソースコード
  https://github.com/ryppl/boost-svn
  boost/context以下、およびlibs/context以下にソースコードお
  よびサンプル、テストがある。
継続は何をするのか
• スレッドがやってることを自前でやる

• ユニプロセッサを考える。
  スレッドは一つのプロセッサで複数の処理を同時に実行する
  ために、
  「少し実行してコンテキスト内のスタックを一旦保存して別な
  コンテキストに切り替えて…」
  ということをおこなっている。

• 継続と呼ばれる概念では、このコンテキストスイッチを自前で
  行うことにより、いくつかのケースのプログラムを自然な流れ
  で書くことができる。
基本的な使い方
• boost::contexts::contextというクラスのコンストラクタで以下を
  設定する:
  –   resume()時に呼ばれる関数
  –   スタックサイズ
  –   最後にデストラクタを呼ぶかどうか
  –   呼び元に必ず戻るかどうか
• context::suspend()メンバ関数
  – コンテキストを中断
• context::resume()メンバ関数
  – コンテキストを再開
• context::start()メンバ関数
  – コンテキストを開始(2回目以降はresume()を呼ぶ)
継続クラス(contextのラッパー)
#include <boost/context/all.hpp>
#include <boost/function.hpp>
#include <boost/utility/value_init.hpp>

class continuation {
  boost::contexts::context ctx_;
  boost::function<void(continuation&)> fn_;
  boost::initialized<bool> started_;
  boost::initialized<bool> is_break_;

 void trampoline_() { fn_(*this); }

public:
  continuation() {}
継続クラス(contextのラッパー)
continuation(boost::function<void(continuation&)> const& fn)
{
  ctx_ = boost::contexts::context(
              &continuation::trampoline_,
              this,
              boost::contexts::default_stacksize(),
              boost::contexts::stack_unwind,
              boost::contexts::return_to_caller);
   fn_ = fn;
}
継続クラス(contextのラッパー)
continuation& operator=(continuation&& other)
{
  // thisに依存してるとmoveできないので作り直し
  ctx_ = boost::contexts::context(
              &continuation::trampoline_,
              this,
              boost::contexts::default_stacksize(),
              boost::contexts::stack_unwind,
              boost::contexts::return_to_caller);

    fn_ = boost::move(other.fn_);
    started_ = boost::move(other.started_);
    is_break_ = boost::move(other.is_break_);
    return *this;
}
継続クラス(contextのラッパー)
int resume()
{
  if (!started_.data()) {
    started_.data() = true;
    is_break_.data() = false;
    return ctx_.start();
  }
  else { return ctx_.resume(); }
}

int restart()
{
  started_.data() = false;
  is_break_.data() = false;
  ctx_ = boost::contexts::context(
              &continuation::trampoline_,
              this,
              boost::contexts::default_stacksize(),
              boost::contexts::stack_unwind,
              boost::contexts::return_to_caller);
  return resume();
}
継続クラス(contextのラッパー)
     int suspend(int vp = 0)
     { return ctx_.suspend(vp); }

     int suspend_break(int vp = 0)
     {
       is_break_.data() = true;
       return ctx_.suspend(vp);
     }

     bool is_complete() const
     { return is_break_.data() || ctx_.is_complete(); }

     void unwind_stack() { ctx_.unwind_stack(); }
};
考えられる基本的なユースケース

• 非同期処理の逐次化
 – コールバック地獄の解消
• (ゲームループなど)継続的に実行する処理の逐次化
 – ファイルの読み込み、シューティングゲームの弾道など
• リスト処理の遅延評価のようなこと
 – C#のyield return/IEnumerableみたいなこと
 – イテレータ/ジェネレータ
非同期処理の逐次化

通常の非同期処理                継続バージョン
void foo()              async_xxx(…, complete);
{                       suspend();
  async_xxx(…, bar);
}                       async_xxx(…, complete);
                        suspend();
void bar()
{                       …
  async_xxx(…, hoge);
}                       void complete()
                        {
void hoge();              resume();
                        }
コールバック関数をあちこちに書く
                        非同期処理を実行
                        → 中断
                        → コールバック関数内で再開を指示
非同期処理の逐次化
class Client {
  io_service& io_service_;
  socket socket_;

 continuation cont_;
 error_code ec_;

public:
  Client(io_service& io_service)
    : io_service_(io_service), socket_(io_service)
  {
    cont_ = continuation(bind(&Client::do_, this));
  }

 void start()
 {
   ec_ = error_code();
   cont_.resume();
 }
 …
非同期処理の逐次化
private:
  void do_()
  {
    while (!ec_) {
      const string req = "ping¥n";
      async_write(socket_, buffer(req), bind(…, completion_handler));
      cont_.suspend();

         if (ec_) break;

         streambuf rep;
         async_read_until(socket_, rep, '¥n', bind(…, completion_handler));
         cont_.suspend();

         if (ec_) break;

         cout << buffer_cast<const char*>(rep.data());
     }

     cout << ec_.message() << endl;
 }
非同期処理の逐次化
     void completion_handler(const error_code& ec)
     {
       ec_ = ec;
       cont_.resume();
     }
};


asio::io_service io_service;
Client client(io_service);

client.start();

io_service.run();




             http://d.hatena.ne.jp/faith_and_brave/20120329/1333008572
(ゲームループなど)継続的に実行する処理の逐次化

通常の定期実行処理                   継続バージョン
// 定期的に呼ばれる関数               // 定期的に呼ばれる関数
void updatePosition()       void updatePosition()
{                           {
  switch (count_) {           x = 0; y = 0; suspend();
    case 0: x = 0; y = 0;     x = 1; y = 0; suspend();
    case 1: x = 1; y = 0;     x = 1; y = 1; suspend();
    case 2: x = 1; y = 1;     x = 0; y = 1; suspend();
    case 3: x = 0; y = 1;     x = 0; y = 0; suspend();
    case 4: x = 0; y = 0;   }
  }
  count_++;
}


どこまで実行したかを自分で覚              次回呼ばれたときに次の行を実行
えておき、次回呼ばれたときに              (自然な流れ)
状態に合わせた地点から実行
(ゲームループなど)継続的に実行する処理の逐次化
class Game {
  vector<string> data;
  continuation cont;
public:
  Game()
    : cont(bind(&Game::load_file, this)) {}

 void update()
 {
   if (!cont.is_complete()) {
       cont.resume();
       cout << data.back() << endl;
   }
 }

 void draw() {}
(ゲームループなど)継続的に実行する処理の逐次化
private:
   void load_file()
   {
     ifstream file("a.txt");
     string line;
     while (std::getline(file, line)) {
       data.push_back(line);
       if (file.peek() != EOF) {
         cont.suspend();
       }
     }
   }
};
(ゲームループなど)継続的に実行する処理の逐次化
const milliseconds timer_duration(static_cast<int>(1.0 / 60.0 * 1000));

void on_timer(Game& game, steady_timer& timer)
{
  game.update();
  game.draw();

    timer.expires_from_now(timer_duration);
    timer.async_wait(
      bind(&on_timer, ref(game), ref(timer)));
}

Game game;
io_service io_service;
steady_timer timer(io_service);

timer.expires_from_now(timer_duration);
timer.async_wait(
         bind(&on_timer, ref(game), ref(timer)));

io_service.run();
         http://d.hatena.ne.jp/faith_and_brave/20120312/1331537869
リスト処理の遅延評価
// nから始まる無限リスト
void enum_from(continuation& cont, int n)
{
  for (int i = n;; ++i) {
    cont.suspend(i);
  }
}

int main()
{
  continuation cont(bind(enum_from, _1, 3));

    // 3から始まる無限リストから先頭10個を取り出す
    for (int i = 0; i < 10; ++i) {
      int n = cont.resume();
      cout << n << endl;
    }
}

          これを抽象化したBoost.Enumeratorというのが開発されている
          https://github.com/jamboree/boost.enumerator
中断可能なアルゴリズム

• 中断可能なアルゴリズムを後付で作れないかと試した。
  Boost.Graphでの最短経路の計算を外部から少しずつ実行す
  る。
• Boost.GraphにはEvent Visitorというのがあり、最短経路計算
  において「点が交差したときに指定された関数を呼ぶ」という
  ようなことができる。
  ここに継続を置いてみた。
class path_history_visitor {
  continuation& cont;
public:
  typedef boost::on_discover_vertex event_filter;

     path_history_visitor(continuation& cont) : cont(cont) {}

     template<typename Vertex, typename Graph>
     void operator()(Vertex v, const Graph&)
     {
       std::cout << Names[v] << ' ';
       cont.suspend();
     }
};
int main()
{
  const Graph g = make_graph();
  const Vertex from = S;

    continuation cont = [&](continuation& cont) {
      path_history_visitor vis(cont);

      boost::dijkstra_shortest_paths(g, from,
             boost::visitor(boost::make_dijkstra_visitor(vis)));
    };

    while (!cont.is_complete()) {
      cont.resume();
    }
}



    ポイントはラムダ式とEvent Visitor。
    Event Visitorは、アルゴリズムの中断ポイントを定義するのに使用できる。
    ラムダは、既存のプログラムをBoost.Contextで使用できるコンテキストに変換するのに使
    用できる。
その他
• ambを実装した
  https://github.com/faithandbrave/Keizoku/tree/master/amb

• Boost.CoroutineがBoost.Contextで書き直されるらしい
  「Boost.Coroutineを用いてステートマシンを解決する – C++Now! 2012」
  https://sites.google.com/site/boostjp/cppnow/2012#coroutine

• Scala設計者のMartin Odersky先生が「Observerパターンやめて継続使お
  うぜ」という論文を書いてる
  「Deprecating the Observer Pattern」
  http://lampwww.epfl.ch/~imaier/pub/DeprecatingObserversTR2010.pdf

More Related Content

What's hot

Synthesijer and Synthesijer.Scala in HLS-friends 201512
Synthesijer and Synthesijer.Scala in HLS-friends 201512Synthesijer and Synthesijer.Scala in HLS-friends 201512
Synthesijer and Synthesijer.Scala in HLS-friends 201512
Takefumi MIYOSHI
 
新しい並列for構文のご提案
新しい並列for構文のご提案新しい並列for構文のご提案
新しい並列for構文のご提案
yohhoy
 
C++ ポインタ ブートキャンプ
C++ ポインタ ブートキャンプC++ ポインタ ブートキャンプ
C++ ポインタ ブートキャンプ
Kohsuke Yuasa
 
Effective modern-c++#9
Effective modern-c++#9Effective modern-c++#9
Effective modern-c++#9
Tatsuki SHIMIZU
 
競技プログラミングのためのC++入門
競技プログラミングのためのC++入門競技プログラミングのためのC++入門
競技プログラミングのためのC++入門
natrium11321
 
Slide
SlideSlide
emc++ chapter32
emc++ chapter32emc++ chapter32
emc++ chapter32
Tatsuki SHIMIZU
 
effective modern c++ chapeter36
effective modern c++ chapeter36effective modern c++ chapeter36
effective modern c++ chapeter36
Tatsuki SHIMIZU
 
競技プログラミングにおけるコードの書き方とその利便性
競技プログラミングにおけるコードの書き方とその利便性競技プログラミングにおけるコードの書き方とその利便性
競技プログラミングにおけるコードの書き方とその利便性
Hibiki Yamashiro
 
Visual C++で使えるC++11
Visual C++で使えるC++11Visual C++で使えるC++11
Visual C++で使えるC++11
nekko1119
 
Effective Modern C++ 読書会 Item 35
Effective Modern C++ 読書会 Item 35Effective Modern C++ 読書会 Item 35
Effective Modern C++ 読書会 Item 35
Keisuke Fukuda
 
Cloud TPU Driver API ソースコード解析
Cloud TPU Driver API ソースコード解析Cloud TPU Driver API ソースコード解析
Cloud TPU Driver API ソースコード解析
Mr. Vengineer
 
BoostAsioで可読性を求めるのは間違っているだろうか
BoostAsioで可読性を求めるのは間違っているだろうかBoostAsioで可読性を求めるのは間違っているだろうか
BoostAsioで可読性を求めるのは間違っているだろうか
Yuki Miyatake
 
組み込みでこそC++を使う10の理由
組み込みでこそC++を使う10の理由組み込みでこそC++を使う10の理由
組み込みでこそC++を使う10の理由kikairoya
 
クロージャデザインパターン
クロージャデザインパターンクロージャデザインパターン
クロージャデザインパターン
Moriharu Ohzu
 
C++でのゲームプログラミングをしたときのお話 札幌C++勉強会 #4 〜スタートゲームプログラミング〜
C++でのゲームプログラミングをしたときのお話 札幌C++勉強会 #4 〜スタートゲームプログラミング〜C++でのゲームプログラミングをしたときのお話 札幌C++勉強会 #4 〜スタートゲームプログラミング〜
C++でのゲームプログラミングをしたときのお話 札幌C++勉強会 #4 〜スタートゲームプログラミング〜
勝成 鈴江
 
Boost.勉強会#19東京 Effective Modern C++とC++ Core Guidelines
Boost.勉強会#19東京 Effective Modern C++とC++ Core GuidelinesBoost.勉強会#19東京 Effective Modern C++とC++ Core Guidelines
Boost.勉強会#19東京 Effective Modern C++とC++ Core Guidelines
Shintarou Okada
 

What's hot (20)

コルーチンを使おう
コルーチンを使おうコルーチンを使おう
コルーチンを使おう
 
Synthesijer and Synthesijer.Scala in HLS-friends 201512
Synthesijer and Synthesijer.Scala in HLS-friends 201512Synthesijer and Synthesijer.Scala in HLS-friends 201512
Synthesijer and Synthesijer.Scala in HLS-friends 201512
 
新しい並列for構文のご提案
新しい並列for構文のご提案新しい並列for構文のご提案
新しい並列for構文のご提案
 
C++ ポインタ ブートキャンプ
C++ ポインタ ブートキャンプC++ ポインタ ブートキャンプ
C++ ポインタ ブートキャンプ
 
Effective modern-c++#9
Effective modern-c++#9Effective modern-c++#9
Effective modern-c++#9
 
競技プログラミングのためのC++入門
競技プログラミングのためのC++入門競技プログラミングのためのC++入門
競技プログラミングのためのC++入門
 
Slide
SlideSlide
Slide
 
emc++ chapter32
emc++ chapter32emc++ chapter32
emc++ chapter32
 
effective modern c++ chapeter36
effective modern c++ chapeter36effective modern c++ chapeter36
effective modern c++ chapeter36
 
More C++11
More C++11More C++11
More C++11
 
競技プログラミングにおけるコードの書き方とその利便性
競技プログラミングにおけるコードの書き方とその利便性競技プログラミングにおけるコードの書き方とその利便性
競技プログラミングにおけるコードの書き方とその利便性
 
Visual C++で使えるC++11
Visual C++で使えるC++11Visual C++で使えるC++11
Visual C++で使えるC++11
 
Effective Modern C++ 読書会 Item 35
Effective Modern C++ 読書会 Item 35Effective Modern C++ 読書会 Item 35
Effective Modern C++ 読書会 Item 35
 
Cloud TPU Driver API ソースコード解析
Cloud TPU Driver API ソースコード解析Cloud TPU Driver API ソースコード解析
Cloud TPU Driver API ソースコード解析
 
BoostAsioで可読性を求めるのは間違っているだろうか
BoostAsioで可読性を求めるのは間違っているだろうかBoostAsioで可読性を求めるのは間違っているだろうか
BoostAsioで可読性を求めるのは間違っているだろうか
 
組み込みでこそC++を使う10の理由
組み込みでこそC++を使う10の理由組み込みでこそC++を使う10の理由
組み込みでこそC++を使う10の理由
 
Map
MapMap
Map
 
クロージャデザインパターン
クロージャデザインパターンクロージャデザインパターン
クロージャデザインパターン
 
C++でのゲームプログラミングをしたときのお話 札幌C++勉強会 #4 〜スタートゲームプログラミング〜
C++でのゲームプログラミングをしたときのお話 札幌C++勉強会 #4 〜スタートゲームプログラミング〜C++でのゲームプログラミングをしたときのお話 札幌C++勉強会 #4 〜スタートゲームプログラミング〜
C++でのゲームプログラミングをしたときのお話 札幌C++勉強会 #4 〜スタートゲームプログラミング〜
 
Boost.勉強会#19東京 Effective Modern C++とC++ Core Guidelines
Boost.勉強会#19東京 Effective Modern C++とC++ Core GuidelinesBoost.勉強会#19東京 Effective Modern C++とC++ Core Guidelines
Boost.勉強会#19東京 Effective Modern C++とC++ Core Guidelines
 

Viewers also liked

C++0xの概要(デブサミ2010)
C++0xの概要(デブサミ2010)C++0xの概要(デブサミ2010)
C++0xの概要(デブサミ2010)
Akira Takahashi
 
C++0x Variadic Type List
C++0x Variadic Type ListC++0x Variadic Type List
C++0x Variadic Type ListAkira Takahashi
 
俺的英語・中国語の勉強法を晒してみる 2011 10-12
俺的英語・中国語の勉強法を晒してみる 2011 10-12俺的英語・中国語の勉強法を晒してみる 2011 10-12
俺的英語・中国語の勉強法を晒してみる 2011 10-12
俊仁 小林
 

Viewers also liked (6)

C++0xの概要(デブサミ2010)
C++0xの概要(デブサミ2010)C++0xの概要(デブサミ2010)
C++0xの概要(デブサミ2010)
 
Bjarne dont speaking
Bjarne dont speakingBjarne dont speaking
Bjarne dont speaking
 
C++ Now 2012 report
C++ Now 2012 reportC++ Now 2012 report
C++ Now 2012 report
 
C++0x Variadic Type List
C++0x Variadic Type ListC++0x Variadic Type List
C++0x Variadic Type List
 
俺的英語・中国語の勉強法を晒してみる 2011 10-12
俺的英語・中国語の勉強法を晒してみる 2011 10-12俺的英語・中国語の勉強法を晒してみる 2011 10-12
俺的英語・中国語の勉強法を晒してみる 2011 10-12
 
Boost Tour 1.50.0 All
Boost Tour 1.50.0 AllBoost Tour 1.50.0 All
Boost Tour 1.50.0 All
 

Similar to Continuation with Boost.Context

Boost9 session
Boost9 sessionBoost9 session
Boost9 sessionfreedom404
 
x86とコンテキストスイッチ
x86とコンテキストスイッチx86とコンテキストスイッチ
x86とコンテキストスイッチ
Masami Ichikawa
 
Scalaの限定継続の応用と基本(改訂版)
Scalaの限定継続の応用と基本(改訂版)Scalaの限定継続の応用と基本(改訂版)
Scalaの限定継続の応用と基本(改訂版)
Kota Mizushima
 
Scalaの限定継続の応用と基本
Scalaの限定継続の応用と基本Scalaの限定継続の応用と基本
Scalaの限定継続の応用と基本
Kota Mizushima
 
for JSDeferred Code Reading
for JSDeferred Code Readingfor JSDeferred Code Reading
for JSDeferred Code ReadingKenichirou Oyama
 
SystemC Tutorial
SystemC TutorialSystemC Tutorial
SystemC Tutorialkocha2012
 
Flow.js
Flow.jsFlow.js
Flow.js
uupaa
 
ラボユース最終成果報告会(Web公開版)
ラボユース最終成果報告会(Web公開版)ラボユース最終成果報告会(Web公開版)
ラボユース最終成果報告会(Web公開版)Shinichi Awamoto
 
Dive into RTS - another side
Dive into RTS - another sideDive into RTS - another side
Dive into RTS - another sideKiwamu Okabe
 
CEDEC 2018 最速のC#の書き方 - C#大統一理論へ向けて性能的課題を払拭する
CEDEC 2018 最速のC#の書き方 - C#大統一理論へ向けて性能的課題を払拭するCEDEC 2018 最速のC#の書き方 - C#大統一理論へ向けて性能的課題を払拭する
CEDEC 2018 最速のC#の書き方 - C#大統一理論へ向けて性能的課題を払拭する
Yoshifumi Kawai
 
ぱっと見でわかるC++11
ぱっと見でわかるC++11ぱっと見でわかるC++11
ぱっと見でわかるC++11えぴ 福田
 
PostgreSQL - C言語によるユーザ定義関数の作り方
PostgreSQL - C言語によるユーザ定義関数の作り方PostgreSQL - C言語によるユーザ定義関数の作り方
PostgreSQL - C言語によるユーザ定義関数の作り方Satoshi Nagayasu
 
VerilatorとSystemC
VerilatorとSystemCVerilatorとSystemC
VerilatorとSystemC
Mr. Vengineer
 
Node.js × 音声認識 - 東京Node学園 2012 LT枠 6番目
Node.js × 音声認識 - 東京Node学園 2012 LT枠 6番目Node.js × 音声認識 - 東京Node学園 2012 LT枠 6番目
Node.js × 音声認識 - 東京Node学園 2012 LT枠 6番目
hecomi
 
Linuxのプロセススケジューラ(Reading the Linux process scheduler)
Linuxのプロセススケジューラ(Reading the Linux process scheduler)Linuxのプロセススケジューラ(Reading the Linux process scheduler)
Linuxのプロセススケジューラ(Reading the Linux process scheduler)
Hiraku Toyooka
 
Boost tour 1_44_0
Boost tour 1_44_0Boost tour 1_44_0
Boost tour 1_44_0
Akira Takahashi
 
Android Lecture #03 @PRO&BSC Inc.
Android Lecture #03 @PRO&BSC Inc.Android Lecture #03 @PRO&BSC Inc.
Android Lecture #03 @PRO&BSC Inc.
Yuki Higuchi
 

Similar to Continuation with Boost.Context (20)

Pfi Seminar 2010 1 7
Pfi Seminar 2010 1 7Pfi Seminar 2010 1 7
Pfi Seminar 2010 1 7
 
Boost9 session
Boost9 sessionBoost9 session
Boost9 session
 
x86とコンテキストスイッチ
x86とコンテキストスイッチx86とコンテキストスイッチ
x86とコンテキストスイッチ
 
Scalaの限定継続の応用と基本(改訂版)
Scalaの限定継続の応用と基本(改訂版)Scalaの限定継続の応用と基本(改訂版)
Scalaの限定継続の応用と基本(改訂版)
 
Scalaの限定継続の応用と基本
Scalaの限定継続の応用と基本Scalaの限定継続の応用と基本
Scalaの限定継続の応用と基本
 
for JSDeferred Code Reading
for JSDeferred Code Readingfor JSDeferred Code Reading
for JSDeferred Code Reading
 
SystemC Tutorial
SystemC TutorialSystemC Tutorial
SystemC Tutorial
 
Flow.js
Flow.jsFlow.js
Flow.js
 
ラボユース最終成果報告会(Web公開版)
ラボユース最終成果報告会(Web公開版)ラボユース最終成果報告会(Web公開版)
ラボユース最終成果報告会(Web公開版)
 
Stream2の基本
Stream2の基本Stream2の基本
Stream2の基本
 
Dive into RTS - another side
Dive into RTS - another sideDive into RTS - another side
Dive into RTS - another side
 
Boost Tour 1.50.0
Boost Tour 1.50.0Boost Tour 1.50.0
Boost Tour 1.50.0
 
CEDEC 2018 最速のC#の書き方 - C#大統一理論へ向けて性能的課題を払拭する
CEDEC 2018 最速のC#の書き方 - C#大統一理論へ向けて性能的課題を払拭するCEDEC 2018 最速のC#の書き方 - C#大統一理論へ向けて性能的課題を払拭する
CEDEC 2018 最速のC#の書き方 - C#大統一理論へ向けて性能的課題を払拭する
 
ぱっと見でわかるC++11
ぱっと見でわかるC++11ぱっと見でわかるC++11
ぱっと見でわかるC++11
 
PostgreSQL - C言語によるユーザ定義関数の作り方
PostgreSQL - C言語によるユーザ定義関数の作り方PostgreSQL - C言語によるユーザ定義関数の作り方
PostgreSQL - C言語によるユーザ定義関数の作り方
 
VerilatorとSystemC
VerilatorとSystemCVerilatorとSystemC
VerilatorとSystemC
 
Node.js × 音声認識 - 東京Node学園 2012 LT枠 6番目
Node.js × 音声認識 - 東京Node学園 2012 LT枠 6番目Node.js × 音声認識 - 東京Node学園 2012 LT枠 6番目
Node.js × 音声認識 - 東京Node学園 2012 LT枠 6番目
 
Linuxのプロセススケジューラ(Reading the Linux process scheduler)
Linuxのプロセススケジューラ(Reading the Linux process scheduler)Linuxのプロセススケジューラ(Reading the Linux process scheduler)
Linuxのプロセススケジューラ(Reading the Linux process scheduler)
 
Boost tour 1_44_0
Boost tour 1_44_0Boost tour 1_44_0
Boost tour 1_44_0
 
Android Lecture #03 @PRO&BSC Inc.
Android Lecture #03 @PRO&BSC Inc.Android Lecture #03 @PRO&BSC Inc.
Android Lecture #03 @PRO&BSC Inc.
 

More from Akira Takahashi

Cpp20 overview language features
Cpp20 overview language featuresCpp20 overview language features
Cpp20 overview language features
Akira Takahashi
 
Cppmix 02
Cppmix 02Cppmix 02
Cppmix 02
Akira Takahashi
 
Cppmix 01
Cppmix 01Cppmix 01
Cppmix 01
Akira Takahashi
 
Modern C++ Learning
Modern C++ LearningModern C++ Learning
Modern C++ Learning
Akira Takahashi
 
cpprefjp documentation
cpprefjp documentationcpprefjp documentation
cpprefjp documentation
Akira Takahashi
 
C++1z draft
C++1z draftC++1z draft
C++1z draft
Akira Takahashi
 
Boost tour 1_61_0 merge
Boost tour 1_61_0 mergeBoost tour 1_61_0 merge
Boost tour 1_61_0 merge
Akira Takahashi
 
Boost tour 1_61_0
Boost tour 1_61_0Boost tour 1_61_0
Boost tour 1_61_0
Akira Takahashi
 
error handling using expected
error handling using expectederror handling using expected
error handling using expected
Akira Takahashi
 
Boost tour 1.60.0 merge
Boost tour 1.60.0 mergeBoost tour 1.60.0 merge
Boost tour 1.60.0 merge
Akira Takahashi
 
Boost tour 1.60.0
Boost tour 1.60.0Boost tour 1.60.0
Boost tour 1.60.0
Akira Takahashi
 
C++14 solve explicit_default_constructor
C++14 solve explicit_default_constructorC++14 solve explicit_default_constructor
C++14 solve explicit_default_constructorAkira Takahashi
 

More from Akira Takahashi (20)

Cpp20 overview language features
Cpp20 overview language featuresCpp20 overview language features
Cpp20 overview language features
 
Cppmix 02
Cppmix 02Cppmix 02
Cppmix 02
 
Cppmix 01
Cppmix 01Cppmix 01
Cppmix 01
 
Modern C++ Learning
Modern C++ LearningModern C++ Learning
Modern C++ Learning
 
cpprefjp documentation
cpprefjp documentationcpprefjp documentation
cpprefjp documentation
 
C++1z draft
C++1z draftC++1z draft
C++1z draft
 
Boost tour 1_61_0 merge
Boost tour 1_61_0 mergeBoost tour 1_61_0 merge
Boost tour 1_61_0 merge
 
Boost tour 1_61_0
Boost tour 1_61_0Boost tour 1_61_0
Boost tour 1_61_0
 
error handling using expected
error handling using expectederror handling using expected
error handling using expected
 
Boost tour 1.60.0 merge
Boost tour 1.60.0 mergeBoost tour 1.60.0 merge
Boost tour 1.60.0 merge
 
Boost tour 1.60.0
Boost tour 1.60.0Boost tour 1.60.0
Boost tour 1.60.0
 
Boost container feature
Boost container featureBoost container feature
Boost container feature
 
Boost Tour 1_58_0 merge
Boost Tour 1_58_0 mergeBoost Tour 1_58_0 merge
Boost Tour 1_58_0 merge
 
Boost Tour 1_58_0
Boost Tour 1_58_0Boost Tour 1_58_0
Boost Tour 1_58_0
 
C++14 solve explicit_default_constructor
C++14 solve explicit_default_constructorC++14 solve explicit_default_constructor
C++14 solve explicit_default_constructor
 
C++14 enum hash
C++14 enum hashC++14 enum hash
C++14 enum hash
 
Multi paradigm design
Multi paradigm designMulti paradigm design
Multi paradigm design
 
Start Concurrent
Start ConcurrentStart Concurrent
Start Concurrent
 
Programmer mind
Programmer mindProgrammer mind
Programmer mind
 
Boost.Study 14 Opening
Boost.Study 14 OpeningBoost.Study 14 Opening
Boost.Study 14 Opening
 

Continuation with Boost.Context

  • 1. Boost.Contextで継続 高橋 晶(Akira Takahashi) id:faith_and_brave/@cpp_akira 2012/04/08(土) Boost.Contextオンリーイベント
  • 2. Boost.Context • Oliver Kowalkeが作ったBoost.Fiberというライブラリの、コンテ キストスイッチ部分を切り出したライブラリ • Boost 1.49.0時点でtrunkに入ってる • 継続(continuation)、ファイバー(fiber)、コルーチン(coroutine)、 マイクロスレッド(microthread)などなど、いろんな呼び名のあ る技術を実現することができる。
  • 3. 資料などのあるところ • Boost.Context について調べた – melpon日記 http://d.hatena.ne.jp/melpon/20111213/1323704464 • ドキュメント http://ok73.ok.funpic.de/boost/libs/context/doc/html/ • ソースコード https://github.com/ryppl/boost-svn boost/context以下、およびlibs/context以下にソースコードお よびサンプル、テストがある。
  • 4. 継続は何をするのか • スレッドがやってることを自前でやる • ユニプロセッサを考える。 スレッドは一つのプロセッサで複数の処理を同時に実行する ために、 「少し実行してコンテキスト内のスタックを一旦保存して別な コンテキストに切り替えて…」 ということをおこなっている。 • 継続と呼ばれる概念では、このコンテキストスイッチを自前で 行うことにより、いくつかのケースのプログラムを自然な流れ で書くことができる。
  • 5. 基本的な使い方 • boost::contexts::contextというクラスのコンストラクタで以下を 設定する: – resume()時に呼ばれる関数 – スタックサイズ – 最後にデストラクタを呼ぶかどうか – 呼び元に必ず戻るかどうか • context::suspend()メンバ関数 – コンテキストを中断 • context::resume()メンバ関数 – コンテキストを再開 • context::start()メンバ関数 – コンテキストを開始(2回目以降はresume()を呼ぶ)
  • 6. 継続クラス(contextのラッパー) #include <boost/context/all.hpp> #include <boost/function.hpp> #include <boost/utility/value_init.hpp> class continuation { boost::contexts::context ctx_; boost::function<void(continuation&)> fn_; boost::initialized<bool> started_; boost::initialized<bool> is_break_; void trampoline_() { fn_(*this); } public: continuation() {}
  • 7. 継続クラス(contextのラッパー) continuation(boost::function<void(continuation&)> const& fn) { ctx_ = boost::contexts::context( &continuation::trampoline_, this, boost::contexts::default_stacksize(), boost::contexts::stack_unwind, boost::contexts::return_to_caller); fn_ = fn; }
  • 8. 継続クラス(contextのラッパー) continuation& operator=(continuation&& other) { // thisに依存してるとmoveできないので作り直し ctx_ = boost::contexts::context( &continuation::trampoline_, this, boost::contexts::default_stacksize(), boost::contexts::stack_unwind, boost::contexts::return_to_caller); fn_ = boost::move(other.fn_); started_ = boost::move(other.started_); is_break_ = boost::move(other.is_break_); return *this; }
  • 9. 継続クラス(contextのラッパー) int resume() { if (!started_.data()) { started_.data() = true; is_break_.data() = false; return ctx_.start(); } else { return ctx_.resume(); } } int restart() { started_.data() = false; is_break_.data() = false; ctx_ = boost::contexts::context( &continuation::trampoline_, this, boost::contexts::default_stacksize(), boost::contexts::stack_unwind, boost::contexts::return_to_caller); return resume(); }
  • 10. 継続クラス(contextのラッパー) int suspend(int vp = 0) { return ctx_.suspend(vp); } int suspend_break(int vp = 0) { is_break_.data() = true; return ctx_.suspend(vp); } bool is_complete() const { return is_break_.data() || ctx_.is_complete(); } void unwind_stack() { ctx_.unwind_stack(); } };
  • 11. 考えられる基本的なユースケース • 非同期処理の逐次化 – コールバック地獄の解消 • (ゲームループなど)継続的に実行する処理の逐次化 – ファイルの読み込み、シューティングゲームの弾道など • リスト処理の遅延評価のようなこと – C#のyield return/IEnumerableみたいなこと – イテレータ/ジェネレータ
  • 12. 非同期処理の逐次化 通常の非同期処理 継続バージョン void foo() async_xxx(…, complete); { suspend(); async_xxx(…, bar); } async_xxx(…, complete); suspend(); void bar() { … async_xxx(…, hoge); } void complete() { void hoge(); resume(); } コールバック関数をあちこちに書く 非同期処理を実行 → 中断 → コールバック関数内で再開を指示
  • 13. 非同期処理の逐次化 class Client { io_service& io_service_; socket socket_; continuation cont_; error_code ec_; public: Client(io_service& io_service) : io_service_(io_service), socket_(io_service) { cont_ = continuation(bind(&Client::do_, this)); } void start() { ec_ = error_code(); cont_.resume(); } …
  • 14. 非同期処理の逐次化 private: void do_() { while (!ec_) { const string req = "ping¥n"; async_write(socket_, buffer(req), bind(…, completion_handler)); cont_.suspend(); if (ec_) break; streambuf rep; async_read_until(socket_, rep, '¥n', bind(…, completion_handler)); cont_.suspend(); if (ec_) break; cout << buffer_cast<const char*>(rep.data()); } cout << ec_.message() << endl; }
  • 15. 非同期処理の逐次化 void completion_handler(const error_code& ec) { ec_ = ec; cont_.resume(); } }; asio::io_service io_service; Client client(io_service); client.start(); io_service.run(); http://d.hatena.ne.jp/faith_and_brave/20120329/1333008572
  • 16. (ゲームループなど)継続的に実行する処理の逐次化 通常の定期実行処理 継続バージョン // 定期的に呼ばれる関数 // 定期的に呼ばれる関数 void updatePosition() void updatePosition() { { switch (count_) { x = 0; y = 0; suspend(); case 0: x = 0; y = 0; x = 1; y = 0; suspend(); case 1: x = 1; y = 0; x = 1; y = 1; suspend(); case 2: x = 1; y = 1; x = 0; y = 1; suspend(); case 3: x = 0; y = 1; x = 0; y = 0; suspend(); case 4: x = 0; y = 0; } } count_++; } どこまで実行したかを自分で覚 次回呼ばれたときに次の行を実行 えておき、次回呼ばれたときに (自然な流れ) 状態に合わせた地点から実行
  • 17. (ゲームループなど)継続的に実行する処理の逐次化 class Game { vector<string> data; continuation cont; public: Game() : cont(bind(&Game::load_file, this)) {} void update() { if (!cont.is_complete()) { cont.resume(); cout << data.back() << endl; } } void draw() {}
  • 18. (ゲームループなど)継続的に実行する処理の逐次化 private: void load_file() { ifstream file("a.txt"); string line; while (std::getline(file, line)) { data.push_back(line); if (file.peek() != EOF) { cont.suspend(); } } } };
  • 19. (ゲームループなど)継続的に実行する処理の逐次化 const milliseconds timer_duration(static_cast<int>(1.0 / 60.0 * 1000)); void on_timer(Game& game, steady_timer& timer) { game.update(); game.draw(); timer.expires_from_now(timer_duration); timer.async_wait( bind(&on_timer, ref(game), ref(timer))); } Game game; io_service io_service; steady_timer timer(io_service); timer.expires_from_now(timer_duration); timer.async_wait( bind(&on_timer, ref(game), ref(timer))); io_service.run(); http://d.hatena.ne.jp/faith_and_brave/20120312/1331537869
  • 20. リスト処理の遅延評価 // nから始まる無限リスト void enum_from(continuation& cont, int n) { for (int i = n;; ++i) { cont.suspend(i); } } int main() { continuation cont(bind(enum_from, _1, 3)); // 3から始まる無限リストから先頭10個を取り出す for (int i = 0; i < 10; ++i) { int n = cont.resume(); cout << n << endl; } } これを抽象化したBoost.Enumeratorというのが開発されている https://github.com/jamboree/boost.enumerator
  • 21. 中断可能なアルゴリズム • 中断可能なアルゴリズムを後付で作れないかと試した。 Boost.Graphでの最短経路の計算を外部から少しずつ実行す る。 • Boost.GraphにはEvent Visitorというのがあり、最短経路計算 において「点が交差したときに指定された関数を呼ぶ」という ようなことができる。 ここに継続を置いてみた。
  • 22. class path_history_visitor { continuation& cont; public: typedef boost::on_discover_vertex event_filter; path_history_visitor(continuation& cont) : cont(cont) {} template<typename Vertex, typename Graph> void operator()(Vertex v, const Graph&) { std::cout << Names[v] << ' '; cont.suspend(); } };
  • 23. int main() { const Graph g = make_graph(); const Vertex from = S; continuation cont = [&](continuation& cont) { path_history_visitor vis(cont); boost::dijkstra_shortest_paths(g, from, boost::visitor(boost::make_dijkstra_visitor(vis))); }; while (!cont.is_complete()) { cont.resume(); } } ポイントはラムダ式とEvent Visitor。 Event Visitorは、アルゴリズムの中断ポイントを定義するのに使用できる。 ラムダは、既存のプログラムをBoost.Contextで使用できるコンテキストに変換するのに使 用できる。
  • 24. その他 • ambを実装した https://github.com/faithandbrave/Keizoku/tree/master/amb • Boost.CoroutineがBoost.Contextで書き直されるらしい 「Boost.Coroutineを用いてステートマシンを解決する – C++Now! 2012」 https://sites.google.com/site/boostjp/cppnow/2012#coroutine • Scala設計者のMartin Odersky先生が「Observerパターンやめて継続使お うぜ」という論文を書いてる 「Deprecating the Observer Pattern」 http://lampwww.epfl.ch/~imaier/pub/DeprecatingObserversTR2010.pdf