1:thread
それでは、C++11のスレッド・ライブラリを使った版をご覧ください。
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です。
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()ひとつで、完了待ちと結果の参照が行えます。
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;
}
