人生初心者の雑記

すべてにおいてド素人な人がいろんなことを書くよ

boost/coroutine編_Dxlibの非同期処理をstd::threadやboost/coroutineでやる

boostのcoroutineってライブラリがある。弾幕風とかluaとかにyieldってのがあって(あるよね?)関数を途中で止めて、再開するときはその止めたところから始めるってのが、c++でもできる。

これに関してなんだけど、日本語で他のブログとかにある情報探したんだけど、
古い。もうそのコードでは動かない
仕方ないから本家のサンプルを引っ張ってくる。
Asymmetric coroutine - 1.58.0
はい、さっぱりわからん。けどサンプルを実際に動かすと、たしかにfor文とかで、途中で戻ってくる。再開するときは、もとのループ変数を保持したままだ。

#include<boost/coroutine/all.hpp>
#include<iostream>
struct X {
	X(){
		std::cout << "X()" << std::endl;
	}

	~X(){
		std::cout << "~X()" << std::endl;
	}
};

int main(){

	int i = 0;
	boost::coroutines::asymmetric_coroutine<void>::push_type sink(
		[&](boost::coroutines::asymmetric_coroutine<void>::pull_type& source){
		X x;
		for (i = 0;; ++i){
			std::cout << "fn(): " << i << std::endl;
			// transfer execution control back to main()
			source();
		}
	});

	sink();
	sink();
	sink();
	sink();
	sink();

	std::cout << "sink is complete: " << std::boolalpha << !sink << "\n";
	return 0;
}
output:
    X()
    fn(): 0
    fn(): 1
    fn(): 2
    fn(): 3
    fn(): 4
    fn(): 5
    sink is complete: false
    ~X()

coroutineはスレッドを生成しているわけではないので、変数にvolatileはいらない。(たぶんね。もしかしたら見当違いなこといってるかもしれない。)

boost::coroutines::asymmetric_coroutine<void>::push_type sink(
		[&](boost::coroutines::asymmetric_coroutine<void>::pull_type& source){
		X x;
		for (i = 0;; ++i){
			std::cout << "fn(): " << i << std::endl;
			// transfer execution control back to main()
			source();
		}
	});

ミソは、
boost::coroutines::asymmetric_coroutine::push_type のコンストラクタとその引数(↑のsink変数)

source()(↑でいうとforループの中)が呼ばれると、処理が戻ってくる。
ということ。それだけ。それさえ知っとけばできる。詳しいことはしらん


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

std::function<void(boost::coroutines::asymmetric_coroutine<void>::pull_type&)> Cor_generator(int& progress){

	return [&](boost::coroutines::asymmetric_coroutine<void>::pull_type& source){
		progress = 0;
		for (int i = 0;; ++i){
			std::cout << "fn(): " << i << std::endl;
			// transfer execution control back to main()
			progress += 1;
			source();
		}
	};
}

int main(){

	int progress;
	boost::coroutines::asymmetric_coroutine<void>::push_type sink(
		Cor_generator(progress)
		);
	while (progress < 100){
		sink();
	}
	
	std::cout << "sink is complete: " << std::boolalpha << !sink << "\n";
	return 0;
}

boost::coroutines::asymmetric_coroutine::push_type が必要とする引数を返す関数を作った。Cor_generatorがロード関数に相当する