連載
プロフェッショナルVB.NETプログラミング
第31回 残されたいくつかのトピック(その2)
(株)ピーデー
川俣 晶
2003/01/11
|
|
マルチスレッドを同期するSyncLockステートメント
この連載では、マルチスレッド機能については詳しく解説していない。これは、主にマルチスレッド機能はクラス・ライブラリを通じて提供されるものであり、この連載では膨大なクラス・ライブラリに深入りしないとしているためである。しかし、ステートメントとして用意された機能もあるので、それを紹介する。マルチスレッドの同期を取るためのSyncLockステートメントである。まず、マルチスレッドを安易に使ったがために、意図しない動作をするサンプル・プログラムを紹介する。フォーム上にボタンが1個貼り付けられている状態でのサンプル・プログラムである。
1: Public Class Form1
2: Inherits System.Windows.Forms.Form
3:
4: …Windows フォーム デザイナで生成されたコード…
5:
6: Private s As String = ""
7:
8: Private Sub ThreadMain1()
9: Dim i As Integer
10: For i = 0 To 99999
11: s = s + "A"
12: Next
13: Trace.WriteLine("ThreadMain1 done")
14: End Sub
15:
16: Private Sub ThreadMain2()
17: Dim i As Integer
18: For i = 0 To 99999
19: s = s + "A"
20: Next
21: Trace.WriteLine("ThreadMain2 done")
22: End Sub
23:
24: Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
25: Dim thread1 As New System.Threading.Thread(AddressOf ThreadMain1)
26: Dim thread2 As New System.Threading.Thread(AddressOf ThreadMain2)
27: thread1.Start()
28: thread2.Start()
29: End Sub
30:
31: Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
32: Trace.WriteLine(Len(s))
33: End Sub
34: End Class
|
|
マルチスレッドを安易に使ったため意図しない動作をするサンプル・プログラム11 |
これを「ThreadMain1 done」と「ThreadMain2 done」というメッセージを確認してから、フォーム上のボタンを押すと、以下のような結果になった。この結果は条件により変化する可能性がある。
このプログラムは、文字列に100000回1文字を追加するスレッドを2つ実行しているので、最終的な文字列の長さは200000文字になるはずである。しかし、そうなっていないのは、「s = s + "A"」という処理の途中でスレッドが切り替わる場合があるからだ。s + "A"の途中でスレッドが切り替わり、変数sを書き換えてしまえば、正しい長さになるはずがない。
この問題を解消するために、SyncLockステートメントを使用することができる。これを使ったサンプル・プログラムを以下に示す。
1: Public Class Form1
2: Inherits System.Windows.Forms.Form
3:
4: …Windows フォーム デザイナで生成されたコード…
5:
6: Private s As String = ""
7:
8: Private Sub ThreadMain1()
9: Dim i As Integer
10: For i = 0 To 99999
11: SyncLock Me
12: s = s + "A"
13: End SyncLock
14: Next
15: Trace.WriteLine("ThreadMain1 done")
16: End Sub
17:
18: Private Sub ThreadMain2()
19: Dim i As Integer
20: For i = 0 To 99999
21: SyncLock Me
22: s = s + "A"
23: End SyncLock
24: Next
25: Trace.WriteLine("ThreadMain2 done")
26: End Sub
27:
28: Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
29: Dim thread1 As New System.Threading.Thread(AddressOf ThreadMain1)
30: Dim thread2 As New System.Threading.Thread(AddressOf ThreadMain2)
31: thread1.Start()
32: thread2.Start()
33: End Sub
34:
35: Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
36: Trace.WriteLine(Len(s))
37: End Sub
38: End Class
|
|
SyncLockステートメントを使用して排他的に処理するようにしたサンプル・プログラム12 |
これを同様の手順で実行すると結果は以下のようになる。
意図とおりの結果が得られたことが分かるだろう。ここで注目すべき点は、11〜13行目と、21〜23行目のSyncLock文である。SyncLockに続いて記述されたオブジェクト(ここではMeつまりこのフォーム自身)に関するアクセスを調停してくれる。つまり、SyncLock〜End SyncLockの間を実行中のスレッドがあるとき、ほかのスレッドが同じオブジェクトに対するSyncLock文に遭遇すると、他スレッドの処理が終わるまで待たせるのである。これにより、s = s + "A"の処理の途中でほかのスレッドに切り替わり、変数sが書き変わることはなくなるのである。
次回予告
今回に引き続き、次回も残されたいくつかのトピックについて見ていく。次回で本連載もとうとう最終回を迎えることになる。
Insider.NET 記事ランキング
本日
月間