連載:VB 6ユーザーのための
|
|
|
サンプル・プログラム17 − Mutexによる排他制御
サンプル・プログラム16では預金を引き落とす(引き出す)スレッドを1つ作成して実行したが、口座管理に限らず、同じファイルやデータに複数の処理が同時に行われることはよくある。次に、そのような処理の例を見てみよう。
ここではスレッドをもう1つ増やし、同時に処理を実行するようにプログラムを発展させる。また、そのときに起こり得る問題と、その問題を回避するための排他制御についても、追って見ていくこととしよう。
■複数のスレッドを作成・実行する
当然のことながら、フォームのデザインにはまったく変更はない。ただ、コードを記述してスレッドをもう1つ作成し、実行すればいい。ここでは、新しいスレッドは預け入れをするような処理にしてみよう。つまり、decDepositに正の値を代入して、スレッドを作成、実行しようというわけだ。
方法はさほど難しくはない。スレッドを作成、実行するためのコードをもう1つ書けばよい。実はこれまた正しい結果が得られないのだが、取りあえずは動くコードとなっている。ステップを追っていくので、焦らずに一歩ずつ進むこととしよう。
| |||||||||||||||
複数のスレッドを作成し、実行するコード | |||||||||||||||
|
スレッドの作成方法は、最初のプログラムとまったく同じ。 がそのコード。スレッドを作成して、myThread2で参照できるようにしている。 や にある、ThreadクラスのNameプロパティにはスレッドの名前を設定できる。このプロパティには値が1回だけしか設定できないので要注意。これらのコードは、現在どのスレッドが実行されているのかを確認するために付け加えたものだ。
WithDrawプロシージャに目を移してみると、ThreadクラスのCurrentThreadプロパティを利用して、現在のスレッドを取得し、Nameプロパティの値をイミディエイト・ウィンドウに表示していることが分かる。従って、イミディエイト・ウィンドウの表示を見れば、どのスレッドが処理を開始したか、終了したかという状況が分かる。
では、実行結果を見てみよう(図4)。イミディエイト・ウィンドウを見れば、確かに複数のスレッドが実行されていることが分かる。が、フォームに結果として表示された残高が少しおかしい。当初の残高が50000円で、そこから20000円引き落とした後、30000円預けるわけなので、残高は、
50000 − 20000 + 30000 = 60000
となるはずなのだが、結果は30000円になってしまう。
図4 複数のスレッドが同じデータを同時に扱うと結果がおかしくなることがある |
本来は60000となるはずの結果が30000にしかならない。イミディエイト・ウィンドウに表示されたスレッドの処理状況を見ると、引き落としの開始と終了の間に、預け入れの処理が終わってしまっていることが分かる。 |
これでは、せっかく預金した30000円がなかったことになってしまう。スレッドは同時に並行して実行されるので、処理のタイミングによっては、このような問題が起こることがある。
このプログラムの場合、引き落としのスレッドが残高を更新する前に、預け入れのスレッドが残高を読み出しているのが原因だ。図で表してみると、その様子がよく分かる(図5)。
図5 スレッドの処理状況 | ||||||||||||||||||
処理を丁寧に追いかけてみれば、正しい結果が得られない理由が分かる。
|
マルチスレッドのプログラムに限らず、複数のコードから同じデータを同時に取り扱うと、このような問題が起こる危険がある。
問題を回避するための最も簡単な方法としては、スレッドのJoinメソッドを使うという方法も考えられる。しかし、それでは汎用性に欠ける。例えば、Joinメソッドを使って引き落としスレッドの実行が終わるのを待ってから、預け入れスレッドを開始するということもできるが、実際には必ずしも引き落としが先に行われて、預け入れが後で行われるとは限らない。どちらが先に実行されても、データの更新が終わるのを待つようにしなければ意味がない。
より汎用的で確実な方法としては、排他制御が使われる。排他制御とは、特定のデータやコードを利用しているときには、ほかからのアクセスを禁止するという制御のこと。この例であれば、先に残高を読み出したスレッドが残高を書き戻すまで、ほかのスレッドから残高にアクセスすること(実際には残高を読み出して実行するコードの実行)を禁止すればよい。
排他制御を実現する方法にはいくつかの方法があるが、「Mutex(ミューテックス)」を利用するのが簡単だろう。というわけで、次にMutexを利用した排他制御を見ていこう。
INDEX | ||
連載:VB 6ユーザーのための<BR>これならマスターできるVB 2005超入門 | ||
第11回 初めてのマルチスレッドと排他制御入門 | ||
1.サンプル・プログラム16 − 初めてのマルチスレッド・プログラム(1) | ||
2.サンプル・プログラム16 − 初めてのマルチスレッド・プログラム(2) | ||
3.サンプル・プログラム17 − Mutexによる排他制御 | ||
4.Mutexを利用した排他制御を組み込む | ||
「これならマスターできるVB 2005超入門」 |
- 第2回 簡潔なコーディングのために (2017/7/26)
ラムダ式で記述できるメンバの増加、throw式、out変数、タプルなど、C# 7には以前よりもコードを簡潔に記述できるような機能が導入されている - 第1回 Visual Studio Codeデバッグの基礎知識 (2017/7/21)
Node.jsプログラムをデバッグしながら、Visual Studio Codeに統合されているデバッグ機能の基本の「キ」をマスターしよう - 第1回 明瞭なコーディングのために (2017/7/19)
C# 7で追加された新機能の中から、「数値リテラル構文の改善」と「ローカル関数」を紹介する。これらは分かりやすいコードを記述するのに使える - Presentation Translator (2017/7/18)
Presentation TranslatorはPowerPoint用のアドイン。プレゼンテーション時の字幕の付加や、多言語での質疑応答、スライドの翻訳を行える
|
|
- - PR -