2007/08/28(Tue) 20:20:19 編集(投稿者)
■No6960 (えムナウ さん) に返信
> 今回のコードではForm2を実行しているスレッドでは Me.Text = text を通る前に FormClosingイベントを通っていないことが担保されます。
> いかがでしょうか?
これでも、Me.Text = textを通る前に FormClosingイベントを通っていないことは保証できません。
ダメなんです…。
Public Sub WriteLine(ByVal text As String)
Dim lockedFormClose As Boolean
SyncLock formCloseLockObject
lockedFormClose = formClose '(a)
End SyncLock
If Not lockedFormClose Then
If Me.InvokeRequired Then
Me.Invoke(New WriteLineDelegate(AddressOf WriteLine), New Object() {text}) '(b)
Else
Me.Text = text
Me.TextBox1.Text = text
Me.TextBox1.ScrollToCaret()
Me.TextBox1.Focus()
End If
End If
End Sub
上記コードで説明します。
まだフォームの終了処理が始まっていない状態で、
Invokeする側のスレッドが(a)でformCloseを取得します。
FormCloseはその時点でまだfalseなので、lockedFormCloseもfalseとなり、
そのままこのスレッドは(b)まで進みます。
しかしこの間に、フォーム側スレッド、Invokeされる側のスレッドは、
Form.Closingを通過し、formCloseを設定してClosedも通過する可能性があります。
そうすると、Invokeする側のスレッドは、廃棄途中か廃棄ごのControlにInvokeしますので、
エラーを吐くかブロックしてフリーズします。
えむナウさんのコードは(a)から(b)まで非常に短いので、
落ちづらいであろうとは思いますが、
安全なコードとはいえません。
実際に試してもみました。
10プロセス同時に起動し、放置したところ、
2個のプロセスが死亡、残り8個のプロセスが20000〜50000回フォームを閉じたところでフリーズしました。
実用上問題ないといえば無いのですが、
どんなコードを組んでも、スレッドセーフなプログラミングができないというのは、
気分が悪くて仕方ありません。
私の知恵では八方塞です。
どなたか、なにかアイデアをお持ちでしたらぜひ教えてください。
もう試したいことがあるので、
それが終わったら閉じます。
(「解決済み」機能を最近知ったので是非使ってみたい!