C# と VB.NET の質問掲示板

ASP.NET、C++/CLI、Java 何でもどうぞ

C# と VB.NET の入門サイト

Re[3]: 閉じるボタン押下時にフリーズして終了できない


(過去ログ 148 を表示中)

[トピック内 5 記事 (1 - 5 表示)]  << 0 >>

■86599 / inTopicNo.1)  閉じるボタン押下時にフリーズして終了できない
  
□投稿者/ モヒンダー (1回)-(2018/02/20(Tue) 13:28:11)

分類:[VB.NET/VB2005 以降] 


VS2013でVBの開発をしています。

WindowsFormプロジェクトを作成し、子スレッドを2つ用意しています。

子スレッド1、子スレッド2は、それぞれ処理を行い、Formオブジェクトの更新
(TextBoxの値を書き換える等)という作業を行っています。

子スレッドからは直接Formオブジェクトのアクセスができないので、子スレッドから
invokeを使用してメインプロセス側でFormオブジェクトの書き換えを行うようにしています。

また、子スレッドはFormクラスに用意した終了フラグを監視していて、終了フラグがONなら、
コンソールにログを出力してスレッドを終了する仕組みにしています。

フォーム上の×ボタン押下により、FormClosingイベントが発生するので、
FormClosingイベントの処理で、
 終了フラグをON
 Sleepで10秒ほどwait
 子スレッド1の待ち合わせ(thread1.Join())
 子スレッド2の待ち合わせ(thread2.Join())
を行って終了させようと試みているのですが、正常に終了する時と、固まって終了できない場合があります。

固まった場合の状況を見ると、子スレッドが終了を検知したというログが出力されず、
メイン側はthreadXX.join()で止まっている状態です。

推測ですが、メインプロセスがFormClosingイベントに入っている状態で、たまたま子スレッドがinvokeで
Formオブジェクトの更新を行おうとした事が原因で

 ・メインプロセス:子スレッドAの終了待ち
 ・子スレッド  :invokeによるメインプロセスでの描画待ち

という状況になっていると考えられます。

この状況を回避する方法は無いでしょうか?


引用返信 編集キー/
■86600 / inTopicNo.2)  Re[1]: 閉じるボタン押下時にフリーズして終了できない
□投稿者/ shu (1102回)-(2018/02/20(Tue) 13:46:28)
No86599 (モヒンダー さん) に返信

UIイベントでの待ちはよろしくないです。
フラグだけ立てて一旦イベントは終了するのがよいかと思います。

サンプルです。
Imports System.ComponentModel

Public Class Form1
    Private flg1 As FLG
    Private flg2 As FLG
    Private flg3 As FLG

    Private Sub Form1_Shown(sender As Object, e As EventArgs) Handles Me.Shown
        flg1 = New FLG With {.Value = True}
        flg2 = New FLG With {.Value = True}
        flg3 = New FLG With {.Value = True}
        Label1.Text = "start"
        BackgroundWorker1.RunWorkerAsync()
    End Sub

    Private Sub BackgroundWorker1_DoWork(sender As Object, e As DoWorkEventArgs) Handles BackgroundWorker1.DoWork
        Dim isend = False
        Do While Not isend
            Dim f1 = False
            Dim f3 = False
            SyncLock flg1
                f1 = flg1.Value
            End SyncLock
            SyncLock flg3
                f3 = flg3.Value
            End SyncLock

            If Not f1 OrElse Not f3 Then
                Exit Do
            End If
            Threading.Thread.Sleep(100)
        Loop
    End Sub

    Private Sub BackgroundWorker1_RunWorkerCompleted(sender As Object, e As RunWorkerCompletedEventArgs) Handles BackgroundWorker1.RunWorkerCompleted
        Label1.Text = "end"
        flg2.Value = False
        If Not flg1.Value Then
            Me.Close()
        End If
    End Sub

    Private Sub Form1_Closing(sender As Object, e As CancelEventArgs) Handles Me.Closing
        If flg2.Value Then
            e.Cancel = True
            SyncLock flg1
                flg1.Value = False
            End SyncLock
        End If
    End Sub

    Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
        SyncLock flg3
            flg3.Value = False
        End SyncLock
    End Sub
End Class

Public Class FLG
    Public Property Value As Boolean
End Class

引用返信 編集キー/
■86606 / inTopicNo.3)  Re[2]: 閉じるボタン押下時にフリーズして終了できない
□投稿者/ にゃるら (3回)-(2018/02/20(Tue) 15:49:37)
提案としては、こんな感じでしょうか?

・子スレッドの呼び出しをInvokeではなく、BeginInvokeにする
・BeginInvokeで呼ばれるメソッド内で、終了フラグが立っているときは本来の処理を行わないようにしておく
・Closingはフラグだけを立てて、待ち合わせしない
・Main関数のあるProgramクラスで、Apllication.Runの後の部分で子スレッドの終了を待ってあげる
引用返信 編集キー/
■86607 / inTopicNo.4)  Re[2]: 閉じるボタン押下時にフリーズして終了できない
□投稿者/ モヒンダー (2回)-(2018/02/20(Tue) 16:39:58)

shu さん
回答有難うございます。

UIイベントでの待ちを行なわないと言う事は、Closeイベントでjoinしないと言う事ですよね。

トライしてみたのですが、子スレッドのinvoke処理(フォームオブジェクトの更新)で例外が発生してしまいます。
恐らく、メインスレッドでCloseイベント発生した段階で、子スレッド内でのinvoke処理がNGなのかなと思いました。

終了フラグが立っていたらinvoke処理(フォームオブジェクトの更新)に入り込まない様にしてみたのですが、
タイミングによってはすり抜ける場合がありそうです。

一応、コンソール上はエラーにはなりますが、固まることなく終了できましたので、try/catchでinvoke
時のエラーハンドリングを行えば暫定的な対処としては、回避できそうですが...。



引用返信 編集キー/
■86610 / inTopicNo.5)  Re[3]: 閉じるボタン押下時にフリーズして終了できない
□投稿者/ モヒンダー (3回)-(2018/02/20(Tue) 17:34:24)
にゃるら さん
回答有難うございます。

提案頂いた内容で改修した所、うまくいきました。

何回か実行してみましたが、BeginInvokeでの例外が発生しなくなりました。

最後の、

> ・Main関数のあるProgramクラスで、Apllication.Runの後の部分で子スレッドの終了を待ってあげる

この記載だけ、ちょっと理解出来ませんでした。
(WindowsFormプロジェクトで作成した為か、Main関数、Apllication.Run部分が見当たらない...。)

とりあえず、実現できましたので、ご回答下さったshu さん、にゃるら さん

本当にありがとうございました。


解決済み
引用返信 編集キー/


トピック内ページ移動 / << 0 >>

このトピックに書きこむ

過去ログには書き込み不可

管理者用

- Child Tree -