CodeZine(コードジン)

特集ページ一覧

C++11 : スレッド・ライブラリひとめぐり

Visual Studio 2012 RC であそんでみたよ

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

1:thread

 それでは、C++11のスレッド・ライブラリを使った版をご覧ください。

リスト6
void multi(int M, int nthr) {
  vector<thread> thr(nthr);
  vector<int> count(nthr);
  div_range<> rng(2,M,nthr);

  chrono::system_clock::time_point start = chrono::system_clock::now();
  for ( int i = 0; i < nthr; ++i ) {
    thr[i] = thread([&,i](int lo, int hi) { count[i] = count_prime(lo,hi); }, 
                    rng.lo(i), rng.hi(i));
  }
  int result = 0;
  for ( int i = 0; i < nthr; ++i ) {
    thr[i].join();
    result += count[i];
  }
  chrono::duration<double> sec = chrono::system_clock::now() - start;

  cout << result << ' ' << sec.count() << "[sec] : " << nthr << endl;
}

int main() {
  const int M = 100000;
  for ( int i = 1; i < 10; ++i ) multi(M, i);
}

 いかがです? Windows APIによる実装と比べるとあっけないほどに簡単、std::threadのコンストラクタにスレッドのエントリとそれに与える引数とを食わせるだけでスレッドが生成されて動き出します。あとは join() で完了を待つだけ。

 コンストラクタに引き渡すスレッド・エントリは()できるもの、つまりファンクタならなんでもOKです。

リスト7
 void count_prime_function(int lo, int hi, int& result) {
   result = count_prime(lo, hi);
 }

class count_prime_class {
   int& result_;
public:
  count_prime_class(int& result) : result_(result) {}
  void operator()(int lo, int hi) { result_ = count_prime(lo, hi); }
};

void multi(int M) {
  thread thr[3];
  int    count[3];
  div_range<> rng(2,M,3);

  auto count_prime_lambda = [&](int lo, int hi) { count[2] = count_prime(lo,hi); };

  chrono::system_clock::time_point start = chrono::system_clock::now();
  // 関数ポインタ, クラスインスタンス, lambda式からスレッドを作る
  thr[0] = thread(count_prime_function,        rng.lo(0), rng.hi(0), ref(count[0]));
  thr[1] = thread(count_prime_class(count[1]), rng.lo(1), rng.hi(1));
  thr[2] = thread(count_prime_lambda,          rng.lo(2), rng.hi(2));
  for ( thread& t : thr ) t.join();
  chrono::duration<double> sec = chrono::system_clock::now() - start;

  cout << count[0] + count[1] + count[2] << ' '
       << sec.count() << "[sec]" << endl;
}

2:async/future

 threadを使った場合、join()による完了待ちの後、結果の参照(読み取り)を行うのですが、async/futureを使えば完了待ちと結果の参照が簡略化されます。戻り値(結果)を返すファンクタと引数をasyncに与えるとfutureが返ってきます。そのfutureに対するget()ひとつで、完了待ちと結果の参照が行えます。

リスト8
class count_prime_class {
public:
  int operator()(int lo, int hi) { return count_prime(lo, hi); }
};

void multi(int M) {
  future<int> fut[3];
  div_range<> rng(2,M,3);

  auto count_prime_lambda = [&](int lo, int hi) { return count_prime(lo,hi); };

  chrono::system_clock::time_point start = chrono::system_clock::now();
  // 関数ポインタ, クラスインスタンス, lambda式からfutureを作る
  fut[0] = async(count_prime,         rng.lo(0), rng.hi(0));
  fut[1] = async(count_prime_class(), rng.lo(1), rng.hi(1));
  fut[2] = async(count_prime_lambda,  rng.lo(2), rng.hi(2));
  int result = fut[0].get() + fut[1].get() + fut[2].get();
  chrono::duration<double> sec = chrono::system_clock::now() - start;

  cout << result << sec.count() << "[sec]" << endl;
}

  • 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