マルチスレッドを使用したアプリケーションについて
Top -> プログラミング -> WindowsSDK プログラミング -> マルチスレッドを使用したアプリケーションについて
1.マルチスレッドについて

マルチスレッド対応OSにおけるプログラム実行の単位のことで、Windowsはマルチスレッドをサポートしています。

プログラム(プロセスとも呼ぶ)の中で複数のスレッドを実行することができ、実行すると(プロセスを実行する)最低1つのスレッドが作成されます。このスレッドを特にプライマリスレッド(primarythread)と呼びます。

2.マルチスレッドのメリットとデメリット

マルチスレッドを利用することにより、長時間かかる処理を実行してもプライマリスレッド等に影響を及ぼさない、また同時に複数のスレッドと同期を取りながら処理することが出来ます。

デメリットとしては、終了処理が少々面倒、また同期処理にバグがあるとデッドロックの発生、リソース競合発生の可能性があり、最悪の場合プログラムを強制終了させる必要が発生したり、例外関連のエラー等で処理がストップする可能性があります。

3.Win32APIとC言語を利用したスレッドプログラミング

Win32APIとC言語でスレッドを実行する方法は以下の3種類あります。

  1. Win32APIのCreateThread関数、ExitThread関数を使う。
  2. マルチスレッド対応ランタイムライブラリの_beginthread関数、_endthread関数を使う。
  3. マルチスレッド対応ランタイムライブラリの_beginthreadex関数、_endthreadex関数を使う。
4.Win32APIのCreateThread関数、ExitThread関数を使う

この関数郡を使用した場合、マルチスレッド対応ランタイムライブラリを使用せず(標準ランタイムライブラリもだめです)Win32API関数のみで作成される必要があります。

なぜマルチスレッド対応ランタイムライブラリなのに使用したらいけないのか?

そしてメモリリークが発生する関数とは、ランタイム内でバッファをアロケートしているもので、例えば、

asctime()、ctime()、localtime()、gmtime()、mktime()、errno、_doserrno 等

これらの関数群はスレッド終了時に70〜80バイトのメモリリークが発生します。 どうしても使用する場合は、標準ランタイムライブラリを使用し、使用するランタイム関数を再入可能関数群に制限するか、セマフォやクリティカルセッションを使用し再入不可能関数の同期を自分でとる必要があります。

以上のことから、Win32APIのスレッド関数は、わざわざ使わなくても良いのではないかと思われます。 またスレッドハンドルは、CloseHandle関数で明示的に閉じる必要があります。

5.マルチスレッド対応ランタイムライブラリの_beginthread関数、_endthread関数を使う

この関数群は、引数も少なくマルチスレッド対応ランタイムライブラリも初期化するのでC言語でも簡単に使用出来ます。

しかし_endthread関数を実行したり、またスレッド関数が終了した場合、 自動的にスレッドハンドルを閉じてしまうので、 スレッドの終了を待ったり、そのプライオリティ等を変更したり、終了コードを得ること等が不可能です。
またスレッドIDも取得できません。このことは、プログラムの作成上支障をきたすことがあるので、使用可能な状況は限られます。

6.マルチスレッド対応ランタイムライブラリの_beginthreadex関数、_endthreadex関数を使う

Windowsでを利用する場合、この関数群を使用することが一番良いと思われます。

理由として、引数はCreateThread関数と似ており、またマルチスレッド対応ランタイムライブラリも初期化され、 _endthreadex関数を実行したり、スレッド関数が終了してもスレッドハンドルは閉じない、 スレッド終了時にメモリリークも発生しません。

そしてスレッドを待ったり、そのプライオリティ等を変更したり、スレッドIDを取得したり、終了コードを得ることが可能です。 またスレッドハンドルは、CloseHandle関数で明示的に閉じる必要があります。

7.マルチスレッド対応ランタイムライブラリと、標準ランタイムライブラリの違いについて

マルチスレッド対応ランタイムライブラリは、再入可能関数群のみで構成されている。
標準ランタイムライブラリは、再入不可能関数群が多く含まれている。

マルチスレッドを利用する場合、なぜ再入不可能関数群を使用するとだめなのか?

例えば、あるスレッド内にあるランタイム関数の実行中に、OSが実行権を別のスレッドへ移動し同じランタイム関数を実行すると、auto変数(スタック)はスレッドごとにデータを保持するが、静的変数はスレッドごとにデータを持たないため、データ破壊が起こり正常な動作をしなくなります。

すなわち再入不可能関数群とは、静的変数を使用している関数ということになります。
また書籍等でCreateThread関数、ExitThread関数を使用したスレッド内で、ランタイム関数を使用している場合があるのは、auto変数(スタック)のみで作成されているランタイム関数なのでデータ破壊が発生しないのです。

8.スレッド関数のまとめ
関数名 ヘッダーファイル名 closehandle関数で
ハンドルを閉じる必要性
createthread関数
exitthread関数
windows.h(winbase.h内) あり
_beginthread関数
_endthread関数
process.h なし
_beginthreadex関数
_endthreadex関数
process.h あり
9.「Visual C++」でマルチスレッド使用する

「Visual C++ 6.0」の場合

戻る
カウンター