前回のコードを書いたとき、調子に乗って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


スポンサード リンク

この記事のカテゴリ

  • ⇒ まだAsynchronous Agents Libraryは本腰入れて勉強していない