ついに開発環境がVisualStudio2010になったよ。
思えば、2005から始まって2008ときて、ここまで引きずってんのかとちょっと自分でも思ったけどw
で、ですね、色々とまたね、ちんまいことなんだけど、変わってたorz
MTA宣言しなくてもWaitAllが使えるし、プラグマもいらないし。楽になったねぇ。
ついでに、長く長く引っかかってた「EndInvokeを呼ぼうよ」問題にもやっと取りかかれた。
クルミの脳でごめんね、進化遅いんで、遅いなりにやってるもんだから、完璧なモノが欲しい人は、それなりの人の所でソースをあさったほうがいいと思うの。ほんと、ごめんね。識者からすれば「当たり前だろ」とか思う事でも、手さぐりな人間には本当に手さぐりなもんだからさ、試して動かしていくしかないんだわ。
だから、完璧であれ、と言われても無理かな。やれるだけのことはやっていくけどね。
というわけで、今のところの最新ソース。長くなったぞー(笑)
Imports System
Imports System.Threading
Module OrochSample
Delegate Sub DrinkingSAKE()
'酒ツボに酒を準備
Public inSakeTubo As New SakeTubo(2000)
'おろちの首準備
Public orochiHeads As New List(Of OrochiHead)
Public Sub Main()
Try
'本体で首が別々に酒飲みするのを身構える
Dim ts As New ThreadStart(AddressOf OrochiDrinking)
Dim workerThread As New Thread(ts)
workerThread.Start()
workerThread.Join()
Catch ex As Exception
Console.WriteLine("{0}", ex.Message)
End Try
Stop
End Sub
Private Sub OrochiDrinking()
'まずは首を八本で飲んでみる
Dim headCount As Integer = 8
'酔っ払い待ち行列を首の数だけ準備
Dim yoppa(headCount - 1) As WaitHandle
orochiHeads.Capacity = headCount
'酒飲み開始
For i As Integer = 1 To headCount
'飲んだ首から酔っ払いへと
yoppa(i - 1) = HeadDrinking(i).AsyncWaitHandle
Next
'全部の首が酔っ払うか切られるかするまで待機
WaitHandle.WaitAll(yoppa)
End Sub
Private Function HeadDrinking(ByVal headNo As Integer) As IAsyncResult
'指定した番号の首に酒を飲ませる
orochiHeads.Add(New OrochiHead(headNo))
Dim gubi As New DrinkingSAKE(AddressOf orochiHeads(headNo - 1).Drink)
'酒飲み開始とともに、酔っ払い待ち行列へ戻す
Return gubi.BeginInvoke(AddressOf HeadYoppa, gubi)
End Function
'酔っ払い待ち行列に何か戻ってくるたびに動く処理(CallBack)
Private Sub HeadYoppa(ByVal asr As IAsyncResult)
'BeginInvokeで2番目のパラメータに渡しておいたobjectを取得しなおし
Dim yoppa As DrinkingSAKE = asr.AsyncState
'おろちの首クラスを取得
Dim head As OrochiHead = yoppa.Target
'スレッドの後始末
yoppa.EndInvoke(asr)
'エラーがあったかどうかを確認
If head.orochiException IsNot Nothing Then
Console.WriteLine("スサノオさんが{0}番目の首切った!", head.Number)
Else
Console.WriteLine("ぷはーっ! {0}番目の首、飲み終わり!", head.Number)
End If
End Sub
Public Class OrochiHead
'おろちの首クラス
'首が無事なのかどうか
Public orochiException As Exception
'お前は何番目なのかを保持
Private meNumber As Integer
ReadOnly Property Number As Integer
Get
Return meNumber
End Get
End Property
'何番目の首?初期化w
Public Sub New(ByVal headNo As Integer)
meNumber = headNo
End Sub
'酒を飲むメソッド
Public Sub Drink()
Dim nowDrink As Integer
Dim nowNokori As Integer
Dim oneDrink As New Random
Dim oneBreath As New Random
Try
'酒ツボの中の酒を飲み干す
While Not (inSakeTubo.Nomihoshited)
'一回飲むたびに息継ぎ
Thread.Sleep(oneBreath.Next(30, 60))
'酒つぼから飲んでみる
If inSakeTubo.Nomihoshited Then
Console.WriteLine("{0}番目の首「もう酒がねぇよ!!ぷんすか」", meNumber)
Exit Sub
Else
'一回ぐび
nowDrink = oneDrink.Next(1, 100)
nowNokori = inSakeTubo.Nokori
inSakeTubo.Gubi(nowDrink)
If inSakeTubo.Nomihoshited Then
Console.WriteLine("{0}番目の首「ちきしょう!足りねぇよ!{1}のみてぇのに{2}しかねぇ!」", meNumber, nowDrink, nowNokori)
Exit Sub
Else
Console.WriteLine("{0}番目の首が {1} リットル ぐびっ : 残り {2} リットル", meNumber, nowDrink, inSakeTubo.Nokori)
End If
End If
'スサノオさんアップ中
Dim cutNo As New Random
Dim cutHead = cutNo.Next(1, 64)
'どれかの首はねます。運が悪かったら首切りw
If cutHead Mod meNumber = 0 Then
Console.WriteLine("スサノオさん「{0}番目の首はねてやんよ!」", meNumber)
Throw New Exception(String.Format("{0}番目の首は切られてしまった!", meNumber))
End If
End While
Catch ex As Exception
orochiException = ex
End Try
End Sub
End Class
Public Class SakeTubo
'酒つぼクラス
'マルチスレッドでの読み書き保護処理を集約
Private cacheLock As New ReaderWriterLockSlim()
Private innerSake As Integer
'酒つぼの準備
Public Sub New(ByVal litter As Integer)
innerSake = litter
End Sub
'酒の残りはどれくらい?
Public Function Nokori() As Integer
cacheLock.EnterReadLock()
Try
Return innerSake
Finally
cacheLock.ExitReadLock()
End Try
End Function
'ぐびぐびいくぜ!
Public Sub Gubi(ByVal gubigubi As Integer)
Dim retFlag As Boolean = True
cacheLock.EnterWriteLock()
Try
If innerSake > gubigubi Then
innerSake -= gubigubi
Else
innerSake = 0
End If
Finally
cacheLock.ExitWriteLock()
End Try
End Sub
'空っぽにしちゃうぞ!
Public Sub Karappo()
cacheLock.EnterWriteLock()
Try
innerSake = 0
Finally
cacheLock.ExitWriteLock()
End Try
End Sub
'飲み干しちゃったかな?どーかな?
Public Function Nomihoshited() As Boolean
cacheLock.EnterWriteLock()
Try
Return (innerSake.Equals(0))
Finally
cacheLock.ExitWriteLock()
End Try
End Function
End Class
End Module
こんな感じ。ほんまに長いw 簡単にいえば、
- おろちさんの首が酒を飲み始める(BeginInvoke)
- 8本の首がばらばらに動きはじめて、スサノオさんに首切られるor呑み終わる(スレッド処理)
- 呑まれる酒つぼは一つ。酒の量はスレッド間でも同じになるようにLockして処理。
- 戻ってきた首ごとに後始末して、よっぱらいかどうかを調べる(CallBackからEndInvoke)
- 全部の首がスレッド終了したら、プログラムは33行の「Stop」を処理
スレッド内でThrowされた例外を親スレッドでCatchするってのは私の脳味噌ではできないので、例外あったら保存するPublicをもっておいて、処理が終わってからここを見ることで解決することにしたん。
いちお、VisualStudio2010で動いたので、それだと大丈夫だと思う。