CodeZine(コードジン)

特集ページ一覧

マルチスレッドを意識しないマルチスレッド・ライブラリ「Intel Concurent Collections」がおもしろい

  • LINEで送る
  • このエントリーをはてなブックマークに追加
2013/09/03 14:00
目次

 動かしてみましょう、10個の"Hello, world"を同時に着火します。

list04
int main() {
  my_context ctx;
  const int steps = 10;
  cout << "--- let's start ---\n";
  for ( int n = 0; n < steps; ++n ) {
    ctx.tags.put(n); // 着火!!
  }
  cout << "--- all steps activated ---\n";
  ctx.wait();
  cout << "--- that's it. ---\n";
}

 コビトさんが8人いる僕のマシンでの実行結果はこうなりました。

 コビトさんたちがCnCの中で同時に働いている様子が伺えますね。

 itemの入出力を使った例もお見せしましょう。与えられた値の平方根を求めるだけの簡単なお仕事です。

 itemの集合CnC::item_collection<key,value>は辞書になっていて、keyに紐づいたvalueをget/putできます。

list05
#include <iostream>
#include <cmath>
#include <cnc/cnc.h>
using namespace std;

struct my_context;

struct my_step {
  int execute(const int& tag, my_context& ctx) const;
};

struct my_context : public CnC::context<my_context> {
  CnC::step_collection<my_step>    steps;
  CnC::tag_collection<int>         tags;
  CnC::item_collection<int,double> inputs;
  CnC::item_collection<int,double> outputs;

  my_context() : steps(*this), tags(*this), inputs(*this), outputs(*this) {
    tags.prescribes(steps, *this); // tags  は steps   に指示する
    steps.consumes(inputs);        // steps は inputs  を消費する
    steps.produces(outputs);       // steps は outputs を生産する
  }
};

int my_step::execute(const int& tag, my_context& ctx) const {
  double input;
  ctx.inputs.get(tag, input);
  ctx.outputs.put(tag, sqrt(input));
  return CnC::CNC_Success;
}

int main() {
  my_context ctx;
  const int steps = 10;
  // 入力をセットして
  for ( int tag = 0; tag < steps; ++tag ) {
    ctx.inputs.put(tag, static_cast<double>(tag));
  }

  // 着火
  for ( int tag = 0; tag < steps; ++tag ) {
    ctx.tags.put(tag);
  }
  ctx.wait(); // 完了を待って

  // 結果を取り出す
  for ( int tag = 0; tag < steps; ++tag ) {
    double input;
    ctx.inputs.get(tag, input);
    double result;
    ctx.outputs.get(tag, result);
    cout << "sqrt(" << input << ") = " << result << endl;
  }

}

 では次にちょっとした応用例、複利計算をやってみます。複利計算では"n年後の残高"は"(n-1)年後の残高に(1+利率)を掛ける"ことで得られます。なのでn番itemに"n年後の残高"を求めることにすれば、n番stepで"(n-1)番itemを読み(1+利率)を掛けてn番itemに書く"を行わせれば、こいつを数珠つなぎにすることでn年後の残高がn番itemから得られます。

list06
#include <iostream>
#include <cnc/cnc.h>

using namespace std;

struct my_context; // forward decl.

struct my_step {
  int execute(const int& n, my_context& ctx) const;
};

struct my_context : public CnC::context<my_context> {
  CnC::step_collection<my_step>    steps;
  CnC::tag_collection<int>         tags;
  CnC::item_collection<int,double> items;
  double                           rate;  // 利率

  my_context() : steps(*this), tags(*this), items(*this) {
    tags.prescribes(steps, *this); // tags は steps に 指示する
    steps.consumes(items);         // steps は items を消費する
    steps.produces(items);         // steps は items を生産する
  }
};

// n-1年の残高と利率からn年後の残高を求める
int my_step::execute(const int& n, my_context& ctx) const {
  // n 年後の残高は
  double result;
  ctx.items.get(n-1, result); // n-1 年後の残高に
  result *= (1.0 + ctx.rate); // 利率をかけたもの
  ctx.items.put(n, result);   // である
  return CnC::CNC_Success;
}

int main() {
  my_context ctx;
  ctx.rate = 0.05;           // 年利5%の定期預金に
  ctx.items.put(0, 10000.0); // 初年度に1万円預けて
  const int duration = 10;   // 10年間放置するとき

  // 1年後, 2年後, ... 10年後 の残高を求めよ!
  for ( int n = 1; n <= duration; ++n ) {
    ctx.tags.put(n); // ここでstepをkickする
  }
  ctx.wait(); // 終わるのを待って

  // 出力する
  for ( int n = 0; n <= duration; ++n ) {
    double balance;
    ctx.items.get(n, balance);
    cout << balance << endl;
  }
}

 んー...面白みに欠けますね。前段のstepが完了しないと後段のstepが動けない(ctx.items.get()でブロックする)ので、動いてるstepは1つだけなんですよね。


  • LINEで送る
  • このエントリーをはてなブックマークに追加

著者プロフィール

  • επιστημη(エピステーメー)

    C++に首まで浸かったプログラマ。 Microsoft MVP, Visual C++ (2004.01~2018.06) "だった"り わんくま同盟でたまにセッションスピーカやったり 中国茶淹れてにわか茶人を気取ってたり、 あと Facebook とか。 著書: - STL標準...

あなたにオススメ

All contents copyright © 2005-2021 Shoeisha Co., Ltd. All rights reserved. ver.1.5