マルチスレッドプログラミングで総和計算 - その2 std::thread & std::async 編-
2012-08-04 - kawa0810の日記 の続きです.
今回は C++11 で追加された機能の一つである std::thread を用いて総和計算の高速化を考えます.
std::thread と std::async について
std::thread は C++11 から追加されたスレッド操作のライブラリです.std::thread を使用してスレッドを実行することで以下のメリットが得られます.
- スレッドで実行させる関数の返り値と引数を void* にしなくてよい
- 引数は何個でも渡せる + オブジェクトを引数にすることも可能
- 例外処理で扱うことができる
std::thread はプリミティブなオブジェクトであり以下の問題があります.
- スレッド内で例外を投げてはいけない
- 関数の返り値を取得できない
よって,std::thread の代わりに std::packaged_task や std::async の使用が推奨されています.
std::async を用いた総和計算
今回は std::async を用いた総和計算の例を以下に記載します.
/**-------------------- async_sum.cpp --------------------*/ #include <iostream> #include <cstdio> #include <cstdlib> #include <cstring> #include <numeric> #include <thread> #include <future> std::size_t const CACHE_LINE = 32; std::size_t const NUM_THREAD = 4; template<class T> T vec_sum_thread(std::size_t const tid, std::size_t const n, T const* x){ std::size_t len = (n + NUM_THREAD - 1) / NUM_THREAD; std::size_t const beg = tid * len; std::size_t const end = (tid == NUM_THREAD - 1 ? n : beg + len); T sum = 0.0; for(std::size_t i=beg; i<end; ++i){ sum += x[i]; } return sum; } template<class T> T vec_sum(std::size_t const n, T const* x){ std::future<T> thread[NUM_THREAD]; for(std::size_t i=0; i<NUM_THREAD; ++i){ thread[i] = std::async(std::launch::async, vec_sum_thread<T>, i, n, x); } T sum = 0.0; for(std::size_t i=0; i<NUM_THREAD; ++i){ sum += thread[i].get(); } return sum; } int main(void){ std::size_t const n = 1023; float* x; double* y; posix_memalign(reinterpret_cast<void**>(&x), CACHE_LINE, n * sizeof(float)); posix_memalign(reinterpret_cast<void**>(&y), CACHE_LINE, n * sizeof(double)); srand( static_cast<unsigned>(time(NULL)) ); for(std::size_t i=0; i<n; ++i) x[i] = static_cast<float>( rand() ) / RAND_MAX; for(std::size_t i=0; i<n; ++i) y[i] = static_cast<double>( rand() ) / RAND_MAX; std::cout << "Single Precision" << std::endl; std::cout << "- Accumulate: " << std::accumulate(x, x+n, 0.0) << std::endl; std::cout << "- vec_add: " << vec_sum(n, x) << std::endl; std::cout << "\nDouble Precision" << std::endl; std::cout << "- Accumulate: " << std::accumulate(y, y+n, 0.0) << std::endl; std::cout << "- vec_add: " << vec_sum(n, y) << std::endl; free(x); free(y); return 0; }
std::async の使い方
・インクルードするファイル
#include <thread> #include <future>
また,std::thread と std::future, std::async は C++11 から追加されたので gcc でコンパイルする際は -std=c++11 が必要となります
$ g++-mp-4.7 async_sum.cpp -std=c++11
・std::future
std::future は計算処理の同期と結果の取得を提供してくれます.今回は std::async で作成するのでスレッドの生成部分は以下のようになります
std::async(std::launch::async, func, arg1, arg2,...); //std::launch::async: std::async でスレッドを生成 //func: スレッドで実行させる関数 //arg1, arg2,...: 関数の引数.何個でも渡すことが可能
また,関数の返り値を取得したい場合は thread.get() を使用することで返り値を取得することができます.
マルチスレッドプログラミングで総和計算
- その1 Pthread 編: 2012-08-04 - kawa0810の日記
- その2 std::async 編: 2012-08-05 - kawa0810の日記
- その3 Win32 API 編: 2012-08-11 - kawa0810の日記
- その4 OpenMP 編: 2012-08-12 - kawa0810の日記