前回のコードを書いたとき、調子に乗ってGoプログラミング言語のチュートリアル – golang.jpの「多重化」の例もVisual C++のAsynchronous Agents Libraryでの書き直しをやっていました。コードを置いておきます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 | using namespace Concurrency; using std::shared_ptr; using std::make_shared; struct request { int a, b; shared_ptr<unbounded_buffer<int>> replyc; }; typedef std::function<int (int, int)> binOp; void run(binOp op, request req) { auto reply = op(req.a, req.b); asend(*req.replyc, reply); } void server(binOp op, shared_ptr<unbounded_buffer<request>> service, shared_ptr<unbounded_buffer<bool>> quit) { for (;;) { auto selector = make_choice(service.get(), quit.get()); switch (receive(selector)) { case 0: // *serviceから受信 go(std::bind(run, op, selector.value<request>())); break; case 1: // *quitから受信 return; } } } struct server_info { shared_ptr<unbounded_buffer<request>> adder; shared_ptr<unbounded_buffer<bool>> quit; }; server_info startServer(binOp op) { server_info s = { make_shared<unbounded_buffer<request>>(), make_shared<unbounded_buffer<bool>>(), }; go(std::bind(server, op, s.adder, s.quit)); return s; } int main() { auto s = startServer([](int a, int b) { return a + b; }); const int N = 100; request reqs[N]; for (int i = 0; i < N; i++) { auto& req = reqs[i]; req.a = i; req.b = i + N; req.replyc = make_shared<unbounded_buffer<int>>(); asend(*s.adder, req); } for (int i = N - 1; i >= 0; i--) { if (receive(*reqs[i].replyc) != N + 2 * i) { std::cout << "fail at " << i << std::endl; } } std::cout << "done" << std::endl; send(*s.quit, true); } |
go関数は前回と同じもの(スレッドプールでの実行)です。相変わらずshared_ptrだらけであるわけは、元のコードがガベージコレクションのある言語からの移植であるためです。初めからC++脳で考えれば、値渡し・参照渡しやunique_ptrをもっと多用したコードになります(shared_ptr不要と言っているわけではありませんよ、念のため)。
新しく登場しているのがmake_choiceです。これを使うと「複数のソースからどれか1つでも受信したら」ということを表現できます。この例のようにreceiveすると、どれかから値を受信するまで待機することになります。
receiveして受け取る値は、「make_choiceの何番目の引数のオブジェクトから受信したか」というインデックスなのでswitchで分岐しています。そして、valueメンバ関数で値を受け取るという具合です。
今回のコードでは、多値戻り値が登場しました。std::tupleも使ってみましたがしっくりこず、結局戻り値用の構造体server_infoを作っています。
ソースコード全体はこちら: multiplex.cpp。
スポンサード リンク |
この記事のカテゴリ
- VC++ ⇒ まだAsynchronous Agents Libraryは本腰入れて勉強していない