マルチスレッドプログラミングで総和計算 - その3 Win32 API 編-
kawa0810 のブログ の続きです.
今回は Win32 API を用いたマルチスレッドプログラミング方法を取り扱います.
Win32 API を用いてマルチスレッドプログラミング
Win32 API にはスレッドを作成・実行するために以下のような関数が用意されています.また,各関数の詳細は msdn を参照してください.
CreateThread の注意点
msdn の説明を読むと CreateThread を使用する場合は以下の点に注意する必要があるそうです.
C のランタイムライブラリに記録されている関数を使うスレッドは、CreateThread 関数と ExitThread 関数ではなく、C のランタイム関数である beginthread 関数と endthread 関数を使うべきです。この方法に従わないと、ExitThread 関数を呼び出したときにわずかなメモリリークが発生します。
C のランタイムライブラリ(CRT)に記録されている関数とは "Win32 API ではない C の標準ライブラリのこと”をさしているそうです.また,日本語版の msdn はメモリリークが発生するとなっていますがコチラ (CreateThread function (Windows)) をみると
If a thread created using CreateThread calls the CRT, the CRT may terminate the process in low-memory conditions.
「CRT はローメモリ状態のプロセスを終了するかもしれません」となっており,おそらく日本語の誤訳があったのではないかと思われます・・・
(参考: Cランタイムライブラリ - BIGLOBEなんでも相談室)
いずれにせよ CreateThread よりも _beginthread か _beginthreadex のほうがよさそうですね.
ということで,今回は推奨されている _beginthreadex を使用します.
_beginthreadex を用いた総和計算
_beginthreadex を用いた総和計算の例を以下に記載します.
/**-------------------------- beginthread_sum.cpp -----------------------*/ #include <Windows.h> #include <process.h>//_beginthreadex #include <iostream> #include <cstdio> #include <cstdlib> #include <cstring> #include <ctime> #include <numeric> std::size_t const NUM_THREADS = 4; template<class T> struct Bthread_sum{ std::size_t tid; std::size_t n; T const* x; T sum; }; template<class T> static unsigned __stdcall vec_sum_thread(void* arg){ Bthread_sum<T>* param = static_cast<Bthread_sum<T>*>(arg); std::size_t const len = (param->n + NUM_THREADS - 1) / NUM_THREADS; std::size_t const beg = param->tid * len; std::size_t const end = (param->tid == NUM_THREADS - 1) ? param->n : beg+len; param->sum = 0; for(std::size_t i=beg; i<end; ++i){ param->sum += param->x[i]; } _endthreadex(0); return 0; } template<class T> T vec_sum(std::size_t const n, T const* x){ HANDLE hThread[NUM_THREADS]; Bthread_sum<T> param[NUM_THREADS]; for(std::size_t i=0; i<NUM_THREADS; ++i){ param[i].tid = i; param[i].n = n; param[i].x = x; hThread[i] = (HANDLE)_beginthreadex(NULL, 0, vec_sum_thread<T>, ¶m[i], 0, NULL); } WaitForMultipleObjects(NUM_THREADS, hThread, TRUE, INFINITE); for(std::size_t i=1; i<NUM_THREADS; ++i) param[0].sum += param[i].sum; for(std::size_t i=0; i<NUM_THREADS; ++i) CloseHandle(hThread[i]); return param[0].sum; } int main(void){ std::size_t const n = 1023; float* x; double* y; x = static_cast<float*>( malloc(n * sizeof(float)) ); y = static_cast<double*>( malloc(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; }
マルチスレッドプログラミングで総和計算
- その1 Pthread 編: kawa0810 のブログ
- その2 std::async 編: kawa0810 のブログ
- その3 Win32 API 編: kawa0810 のブログ
- その4 OpenMP 編: kawa0810 のブログ