SlideShare a Scribd company logo
Boost.Coroutine
自己紹介
・めるぽん
・SICP(計算機プログラムの構造と解釈)未読
・CTMCP(コンピュータプログラミングの概念・技法・モデル)未読
・D&E未読
・英語本未読
アジェンダ
・Boost.Coroutine とは
・Boost.Coroutine の入手方法
・Boost.Coroutine の使い方
・Boost.Coroutine の実装
・Boost.Coroutine の未来
・Boost.Coroutine のまとめ
Boost.Coroutine とは
・関数の実行を途中で凍結・再実行させる機構
int f(coroutine<int ()>::self& self) {
int n = 0;
while (true) ++n, self.yield(n * n);
self.exit();
}
int main() {
coroutine<int ()> coro(f);
std::cout << coro() << std::endl; // 1 * 1 = 1
std::cout << coro() << std::endl; // 2 * 2 = 4
std::cout << coro() << std::endl; // 3 * 3 = 9
}
Boost.Coroutine とは
・別名: micro-thread, fiber, continuation
・スレッドによく似ている
・コンテキストの切り替えはシステムではなくユーザが手動で行う
・同期が取りやすい

・使い方はいろいろ
・視点を変えると別の意味になったりする

・Boost ライブラリに正式に採用されていない
Boost.Coroutine の入手方法
・Boost.Vault から持ってくる
Boost.Coroutine の入手方法
・Boost.Vault から持ってくる
Boost.Coroutine の入手方法
・Boost.Vault から持ってくる
Boost.Coroutine の入手方法
・Boost.Vault から持ってくる
Boost.Coroutine の使い方
using namespace boost::coroutines;
typedef coroutine<int ()> coro_type;
int f(coro_type::self& self) {
int n = 0;
while (true) ++n, self.yield(n * n);
self.exit();
}
int main() {
coro_type
std::cout
std::cout
std::cout
}

coro(f);
<< coro() << std::endl; // 1 * 1 = 1
<< coro() << std::endl; // 2 * 2 = 4
<< coro() << std::endl; // 3 * 3 = 9
Boost.Coroutine の使い方
using namespace boost::coroutines;
typedef generator<int> gen_type;
int f(gen_type::self& self) {
int n = 0;
while (true) ++n, self.yield(n * n);
self.exit();
}
int main() {
gen_type gen(f);
while (gen != generator_type()) {
*gen; // 1, 4, 9, 16, ...
++gen;
}
}
Boost.Coroutine の使い方
void bullet(point pt)
for (int i = 0; i
for (int i = 0; i
for (int i = 0; i
}

{
< 10; i++) ++pt.x;
< 20; i++) ++pt.y;
< 30; i++) --pt.x;

・こんな弾の動きを作りたい。けど、
void bullet(int& state, point& pt) {
if (0 <= state && state < 10) ++pt.x;
if (10 <= state && state < 30) ++pt.y;
if (30 <= state && state < 60) --pt.x;
++state;
}

・こんな非直感的なコードを書かないといけない
Boost.Coroutine の使い方
point bullet(coro_type::self& self, point pt) {
for (int i = 0; i < 10; i++) ++pt.x, self.yield(pt);
for (int i = 0; i < 20; i++) ++pt.y, self.yield(pt);
for (int i = 0; i < 30; i++) --pt.x, self.yield(pt);
self.exit();
}
class bullet_task {
coro_type coro_;
public:
bullet_task()
: coro_(boost::bind(bullet, _1, point(10, 20)){}
bool move() {
point pt = coro_(std::nothrow);
return coro_;
}
};
Boost.Coroutine の使い方
BOOL EnumWindows(
WNDENUMPROC lpEnumFunc, // コールバック関数
LPARAM lParam // アプリケーション定義の値
);

・コールバックでウインドウを列挙する関数
BOOL CALLBACK callback(HWND hwnd, LPARAM param) {
// hwnd を使ってごにょごにょする
}
int main() {
::EnumWindows(callback, param);
}

・すごく使いにくい
・イテレータみたいな使い方がしたい
Boost.Coroutine の使い方
typedef generator<HWND> gen_type;
BOOL CALLBACK callback(HWND hwnd, LPARAM param) {
gen_type::self& self =
*reinterpret_cast<gen_type::self*>(param);
self.yield(hwnd);
return TRUE;
}
HWND enum_windows(gen_type::self& self) {
::EnumWindows(&callback, reinterpret_cast<LPARAM>(&self));
self.exit();
}
int main() {
gen_type it(enum_windows);
while (it != gen_type()) {
std::cout << (void*)*it << std::endl;
++it;
}
}
Boost.Coroutine の実装
・Windows の場合
・Fiber を使う

・Mac(POSIX) の場合
・ucontext を使う

・Linux の場合
・アセンブラを使う
Boost.Coroutine の実装
・環境によってはコンテキストを自由に作れない
・セキュリティ的に問題あり
・だからこそのFiberやucontext

・組み込み環境で特に有効
・スレッドも使えない上に何ms以内にシステムに返せとか面倒
・アセンブラで自作できる場合が多い
・BREW 環境上(ARM アセンブラ)で作ってみて無事動いた

・実装を知っておくと好きな環境で作れる
Boost.Coroutine の実装
・コンテキストとは
・実行するために必要なもの
void f(coro_type::self& self) {
int a; // a, b はスタックに置かれている
int b; // a, b は yield されても保持されている
self.yield();
}
・スタック
・レジスタ
・(例外情報)

・これらを保存して実行中のコンテキストを切り替える
Boost.Coroutine の実装
・コンテキストの切り替え方
1.必要な情報を保存する
2.スタックポインタを書き換える
3.必要な情報を読み込む
4.プログラムカウンタを書き換える
Boost.Coroutine の実装
・コンテキストの切り替え方
1.必要な情報を保存する
2.スタックポインタを書き換える
3.必要な情報を読み込む
4.プログラムカウンタを書き換える
void f(coro_type::self& self) {
int a;
self.yield();
// pc1
}
coro_type coro(f);
coro();
// pc2
Boost.Coroutine の実装
・コンテキストの切り替え方
1.必要な情報を保存する
2.スタックポインタを書き換える
3.必要な情報を読み込む
4.プログラムカウンタを書き換える
void f(coro_type::self& self) {
int a;
self.yield();
// pc1
}
coro_type coro(f);
coro();
// pc2

Main

SP→
Boost.Coroutine の実装
・コンテキストの切り替え方
1.必要な情報を保存する
2.スタックポインタを書き換える
3.必要な情報を読み込む
4.プログラムカウンタを書き換える
void f(coro_type::self& self) {
int a;
self.yield();
// pc1
}
coro_type coro(f);
coro();
// pc2

Main

SP→

coro

Coroutine
Boost.Coroutine の実装
・コンテキストの切り替え方
1.必要な情報を保存する
2.スタックポインタを書き換える
3.必要な情報を読み込む
4.プログラムカウンタを書き換える
void f(coro_type::self& self) {
int a;
self.yield();
// pc1
}
coro_type coro(f);
coro();
// pc2

Main

Coroutine

0
SP→

coro

&f
Boost.Coroutine の実装
・コンテキストの切り替え方
1.必要な情報を保存する
2.スタックポインタを書き換える
3.必要な情報を読み込む
4.プログラムカウンタを書き換える
void f(coro_type::self& self) {
int a;
self.yield();
// pc1
}
coro_type coro(f);
coro();
// pc2

Main

Coroutine

0
SP→

coro

&f
Boost.Coroutine の実装
・コンテキストの切り替え方
1.必要な情報を保存する
2.スタックポインタを書き換える
3.必要な情報を読み込む
4.プログラムカウンタを書き換える
void f(coro_type::self& self) {
int a;
self.yield();
// pc1
}
coro_type coro(f);
coro();
// pc2

Main
SP→

Coroutine

r0
pc2

0

coro

&f
Boost.Coroutine の実装
・コンテキストの切り替え方
1.必要な情報を保存する
2.スタックポインタを書き換える
3.必要な情報を読み込む
4.プログラムカウンタを書き換える
void f(coro_type::self& self) {
int a;
self.yield();
// pc1
}
coro_type coro(f);
coro();
// pc2

Coroutine

Main
r0
pc2
coro

SP→

0
&f
Boost.Coroutine の実装
・コンテキストの切り替え方
1.必要な情報を保存する
2.スタックポインタを書き換える
3.必要な情報を読み込む
4.プログラムカウンタを書き換える
void f(coro_type::self& self) {
int a;
self.yield();
// pc1
}
coro_type coro(f);
coro();
// pc2

Coroutine

Main
r0
pc2
coro
SP→
Boost.Coroutine の実装
・コンテキストの切り替え方
1.必要な情報を保存する
2.スタックポインタを書き換える
3.必要な情報を読み込む
4.プログラムカウンタを書き換える
void f(coro_type::self& self) {
int a;
self.yield();
// pc1
}
coro_type coro(f);
coro();
// pc2

Coroutine

Main
r0
pc2
coro
SP→
Boost.Coroutine の実装
・コンテキストの切り替え方
1.必要な情報を保存する
2.スタックポインタを書き換える
3.必要な情報を読み込む
4.プログラムカウンタを書き換える
void f(coro_type::self& self) {
int a;
self.yield();
// pc1
}
coro_type coro(f);
coro();
// pc2

Coroutine

Main
r0
pc2
coro

SP→

a
Boost.Coroutine の実装
・コンテキストの切り替え方
1.必要な情報を保存する
2.スタックポインタを書き換える
3.必要な情報を読み込む
4.プログラムカウンタを書き換える
void f(coro_type::self& self) {
int a;
self.yield();
// pc1
}
coro_type coro(f);
coro();
// pc2

Coroutine

Main
r0
pc2
coro

SP→

a
Boost.Coroutine の実装
・コンテキストの切り替え方
1.必要な情報を保存する
2.スタックポインタを書き換える
3.必要な情報を読み込む
4.プログラムカウンタを書き換える
void f(coro_type::self& self) {
int a;
self.yield();
// pc1
}
coro_type coro(f);
coro();
// pc2

Coroutine

Main
r0

SP→

r0

pc2

pc1

coro

a
Boost.Coroutine の実装
・コンテキストの切り替え方
1.必要な情報を保存する
2.スタックポインタを書き換える
3.必要な情報を読み込む
4.プログラムカウンタを書き換える
void f(coro_type::self& self) {
int a;
self.yield();
// pc1
}
coro_type coro(f);
coro();
// pc2

Main
SP→

Coroutine

r0

r0

pc2

pc1

coro

a
Boost.Coroutine の実装
・コンテキストの切り替え方
1.必要な情報を保存する
2.スタックポインタを書き換える
3.必要な情報を読み込む
4.プログラムカウンタを書き換える
void f(coro_type::self& self) {
int a;
self.yield();
// pc1
}
coro_type coro(f);
coro();
// pc2

Main

Coroutine
r0
pc1

SP→

coro

a
Boost.Coroutine の実装
・コンテキストの切り替え方
1.必要な情報を保存する
2.スタックポインタを書き換える
3.必要な情報を読み込む
4.プログラムカウンタを書き換える
void f(coro_type::self& self) {
int a;
self.yield();
// pc1
}
coro_type coro(f);
coro();
// pc2

Main

Coroutine
r0
pc1

SP→

coro

a
Boost.Coroutine の実装
・コンテキストの切り替え方
1.必要な情報を保存する
2.スタックポインタを書き換える
3.必要な情報を読み込む
4.プログラムカウンタを書き換える
pushl %ebp
pushl %ebx
pushl %esi
pushl %edi
movl %esp, (%eax)
movl %edx, %esp
popl %edi
popl %esi
popl %ebx
popl %ebp
ret

PUSH {r0-r12,lr}
STR sp,[r0]
MOV sp,r1
POP {r0-r12,lr}
MOV pc,lr
Boost.Coroutine の実装
・コンテキストの切り替え方
1.必要な情報を保存する
2.スタックポインタを書き換える
3.必要な情報を読み込む
4.プログラムカウンタを書き換える
pushl %ebp
pushl %ebx
pushl %esi
pushl %edi
movl %esp, (%eax)
movl %edx, %esp
popl %edi
popl %esi
popl %ebx
popl %ebp
ret

PUSH {r0-r12,lr}
STR sp,[r0]
MOV sp,r1
POP {r0-r12,lr}
MOV pc,lr
Boost.Coroutine の実装
・コンテキストの切り替え方
1.必要な情報を保存する
2.スタックポインタを書き換える
3.必要な情報を読み込む
4.プログラムカウンタを書き換える
pushl %ebp
pushl %ebx
pushl %esi
pushl %edi
movl %esp, (%eax)
movl %edx, %esp
popl %edi
popl %esi
popl %ebx
popl %ebp
ret

PUSH {r0-r12,lr}
STR sp,[r0]
MOV sp,r1
POP {r0-r12,lr}
MOV pc,lr
Boost.Coroutine の実装
・コンテキストの切り替え方
1.必要な情報を保存する
2.スタックポインタを書き換える
3.必要な情報を読み込む
4.プログラムカウンタを書き換える
pushl %ebp
pushl %ebx
pushl %esi
pushl %edi
movl %esp, (%eax)
movl %edx, %esp
popl %edi
popl %esi
popl %ebx
popl %ebp
ret

PUSH {r0-r12,lr}
STR sp,[r0]
MOV sp,r1
POP {r0-r12,lr}
MOV pc,lr
Boost.Coroutine の実装
・コンテキストの切り替え方
1.必要な情報を保存する
2.スタックポインタを書き換える
3.必要な情報を読み込む
4.プログラムカウンタを書き換える
pushl %ebp
pushl %ebx
pushl %esi
pushl %edi
movl %esp, (%eax)
movl %edx, %esp
popl %edi
popl %esi
popl %ebx
popl %ebp
ret

PUSH {r0-r12,lr}
STR sp,[r0]
MOV sp,r1
POP {r0-r12,lr}
MOV pc,lr
Boost.Coroutine の実装
・他の方法で実装するのもあり
・機械的に状態マシンに置き換える(C#)
IEnumerable<int> GetEnumerator() {
yield return 2;
yield return 4;
}
int state, result;
int GetCurrent() {
bool MoveNext() {
switch (state)
case 0: result
case 1: result
case 2: return
}
}

result; }
{
= 2; state = 1; return true;
= 4; state = 2; return true;
false;
Boost.Coroutine の実装
・他の方法で実装するのもあり
・スレッドを使って実装する
・アセンブラが直接弄れないけど Coroutine が使いたい!(Java とか)
public final class Coro implements CoroutineFunction {
public void coro(Coroutine.Self self) {
self.yield();
self.yield();
}
}
Coroutine c = new Coroutine(new Coro());
c.coro();
Boost.Coroutine の未来
・Boost.ML を追いかけた
・2008/7/26 に sandbox 上の Boost.Coroutine を更新している
・複雑になりすぎたのでもっと単純なインターフェースにするとか何とか

・作者は ML には結構出てきてるのでちゃんと元気にしてるっぽい
・やる気が無い?

・作者以外の人が頑張っている
・Mac 版の対応
・バグの修正

・Boost.Coroutine の未来
・正式に採用されるのかどうか分からない
・Boost.Fiber という対抗馬も最近出てきた
Boost.Coroutine のまとめ
・手動マルチスレッド
・いろいろな使い方ができる
・実装はスタックポインタの書き換え
・それ以外の方法で実装するのもあり

・Boost.Coroutine は実装の模範例
・利用は自己責任
おわり

More Related Content

PDF
プログラムを高速化する話
PPTX
QEMU - Binary Translation
PDF
謎の言語Forthが謎なので実装した
PDF
20分くらいでわかった気分になれるC++20コルーチン
PDF
LLVM最適化のこつ
ODP
括弧への異常な愛情 または私は如何にして心配するのを止めてCommon Lispを愛するようになったか
PDF
Qemu JIT Code Generator and System Emulation
PDF
The Internals of "Hello World" Program
プログラムを高速化する話
QEMU - Binary Translation
謎の言語Forthが謎なので実装した
20分くらいでわかった気分になれるC++20コルーチン
LLVM最適化のこつ
括弧への異常な愛情 または私は如何にして心配するのを止めてCommon Lispを愛するようになったか
Qemu JIT Code Generator and System Emulation
The Internals of "Hello World" Program

What's hot (20)

PDF
Android カスタムROMの作り方
PDF
Virtual Machine Constructions for Dummies
PDF
Ethernetの受信処理
PDF
SONiCインストールしてみた
PDF
Binderのはじめの一歩とAndroid
PDF
そろそろRStudioの話
ODP
スレッドダンプの読み方
PDF
PG-REXで学ぶPacemaker運用の実例
PPTX
サーバサイドの並行プログラミング〜かんたんマルチスレッドプログラミング〜
PDF
Marp入門
PDF
SFO15-202: Towards Multi-Threaded Tiny Code Generator (TCG) in QEMU
PDF
文字コードに起因する脆弱性とその対策(増補版)
PDF
Dockerからcontainerdへの移行
PDF
NAND Flash から InnoDB にかけての話(仮)
PDF
きつねさんでもわかるLlvm読書会 第2回
PDF
Dalvik仮想マシンのアーキテクチャ 改訂版
PPTX
Understand more about C
PDF
Blazing Performance with Flame Graphs
PDF
PostgreSQL 15の新機能を徹底解説
PDF
1076: CUDAデバッグ・プロファイリング入門
Android カスタムROMの作り方
Virtual Machine Constructions for Dummies
Ethernetの受信処理
SONiCインストールしてみた
Binderのはじめの一歩とAndroid
そろそろRStudioの話
スレッドダンプの読み方
PG-REXで学ぶPacemaker運用の実例
サーバサイドの並行プログラミング〜かんたんマルチスレッドプログラミング〜
Marp入門
SFO15-202: Towards Multi-Threaded Tiny Code Generator (TCG) in QEMU
文字コードに起因する脆弱性とその対策(増補版)
Dockerからcontainerdへの移行
NAND Flash から InnoDB にかけての話(仮)
きつねさんでもわかるLlvm読書会 第2回
Dalvik仮想マシンのアーキテクチャ 改訂版
Understand more about C
Blazing Performance with Flame Graphs
PostgreSQL 15の新機能を徹底解説
1076: CUDAデバッグ・プロファイリング入門
Ad

Similar to Boost.Coroutine (20)

PDF
Boost Tour 1_58_0 merge
ODP
Boost9 session
PDF
コルーチンを使おう
PDF
Boost Tour 1.53.0 merge
PDF
C++14 Overview
PDF
Continuation with Boost.Context
PDF
Scope Exit
PDF
20190625 OpenACC 講習会 第2部
PDF
Async design with Unity3D
PPTX
ぱっと見でわかるC++11
PDF
Boost Fusion Library
PDF
Pfi Seminar 2010 1 7
PDF
コルーチンの使い方
PPTX
冬のLock free祭り safe
KEY
Objc lambda
PDF
新しい並列for構文のご提案
PDF
Boost Tour 1.53.0
PDF
Boost Tour 1.48.0 diff
PDF
Boost Tour 1.50.0 All
PDF
boost tour 1.48.0 all
Boost Tour 1_58_0 merge
Boost9 session
コルーチンを使おう
Boost Tour 1.53.0 merge
C++14 Overview
Continuation with Boost.Context
Scope Exit
20190625 OpenACC 講習会 第2部
Async design with Unity3D
ぱっと見でわかるC++11
Boost Fusion Library
Pfi Seminar 2010 1 7
コルーチンの使い方
冬のLock free祭り safe
Objc lambda
新しい並列for構文のご提案
Boost Tour 1.53.0
Boost Tour 1.48.0 diff
Boost Tour 1.50.0 All
boost tour 1.48.0 all
Ad

Boost.Coroutine