SlideShare ist ein Scribd-Unternehmen logo
1 von 24
Downloaden Sie, um offline zu lesen
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

Weitere ähnliche Inhalte

Was ist angesagt?

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 201512Takefumi MIYOSHI
 
新しい並列for構文のご提案
新しい並列for構文のご提案新しい並列for構文のご提案
新しい並列for構文のご提案yohhoy
 
C++ ポインタ ブートキャンプ
C++ ポインタ ブートキャンプC++ ポインタ ブートキャンプ
C++ ポインタ ブートキャンプKohsuke Yuasa
 
競技プログラミングのためのC++入門
競技プログラミングのためのC++入門競技プログラミングのためのC++入門
競技プログラミングのためのC++入門natrium11321
 
effective modern c++ chapeter36
effective modern c++ chapeter36effective modern c++ chapeter36
effective modern c++ chapeter36Tatsuki SHIMIZU
 
競技プログラミングにおけるコードの書き方とその利便性
競技プログラミングにおけるコードの書き方とその利便性競技プログラミングにおけるコードの書き方とその利便性
競技プログラミングにおけるコードの書き方とその利便性Hibiki Yamashiro
 
Visual C++で使えるC++11
Visual C++で使えるC++11Visual C++で使えるC++11
Visual C++で使えるC++11nekko1119
 
Effective Modern C++ 読書会 Item 35
Effective Modern C++ 読書会 Item 35Effective Modern C++ 読書会 Item 35
Effective Modern C++ 読書会 Item 35Keisuke 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 GuidelinesShintarou Okada
 

Was ist angesagt? (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
 

Andere mochten auch

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俊仁 小林
 

Andere mochten auch (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
 

Ähnlich wie 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.jsuupaa
 
ラボユース最終成果報告会(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
 
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
 
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
 

Ähnlich wie 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.
 

Mehr von 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