ウォッチドッグタイマーの実装方法

解決


Kura  2012-05-10 06:05:16  No: 103282  IP: 192.*.*.*

Windowsフォーム・アプリケーションである処理(Hoge.main)を数万回
繰り返し実行していますが、この処理がごく稀にフリーズしてので1分間
のウォッチドッグタイマを作っています。
タイマ起動時の呼び出し元側(Class From1)と呼び出し先(Class test)で
安全に終了処理させる仕方が判りません。
どなたがご教授お願いします。

<呼び出し元>
Public Class Form1

    Private Sub Form1_Load(ByVal sender ・・・・・
        Hoge.Main()
    【質問1】Class testをタイマにより強制的に抜けてきた場合の処理
    End Sub
End Class

<呼び出し先>
Public Class test
  Public Shared Sub Main()
    Dim timerCallback As _
      New TimerCallback(AddressOf WatchdogTimer) '
    ' Watch dog Timerとして、1分後にtimerCallbackメソッドを呼び出す
    Dim timer As New Timer( _
      timerCallback, Nothing, 60 * 1000, 0) '

      ・
      (数万回の繰り返し処理を実装)
      ・

End Sub

  'Watch dog Timerの処理
  Private Shared Sub WatchdogTimer(state As Object) '
    msgbox "フリーズしているので強制終了します"
    【質問2】Class testを強制的に抜けるには?
  End Sub

End Class

編集 削除
魔界の仮面弁士  2012-05-10 12:56:25  No: 103283  IP: 192.*.*.*

ここは VB2-VB6専用 の掲示板です。
VB.NET の場合は隣の掲示板を利用してください。


とりあえず一般論として:
・Main メソッドは、一般的にはスタートアッププロシージャー
  (エントリーポイント)として利用される名前のため、
  呼び出し先メソッド名を "Main" とするのは好ましくありません。
・UIスレッドのイベント(Form_Load 等)に時間のかかる処理を記述しない。


> である処理(Hoge.main)
>
> Private Sub Form1_Load(ByVal sender ・・・・・
>    Hoge.Main()
>
> Public Class test
>   Public Shared Sub Main()

「hoge.Main」「Hoge.Main」と
「test.Main」の関係が説明されていません。


> 安全に終了処理させる仕方が判りません。

ループ処理内に、逐次経過時間による「タイムアウト」を判定文を入れて
1分を越えたらループ処理を打ち切るような実装もあれば、
ループ処理部を別スレッドにしておき、メインスレッドから打ち切り要請を
発行するパターン(BackgroundWorker.CancelAsync メソッドなど)、あるいは
ワーカースレッドを 1 分後に Abort する方法などが思いつきますが、
何をもって「安全な終了」とするのかは、ケースバイケースですよね。

たとえば終了時には、ロールバック処理、各種APIハンドルの解放処理、
一時ファイルの削除等々が必要になるようなケースも考えられますが、
どんな処理を行っているのか分からないので、何とも言えないです。


> がごく稀にフリーズしてので
「処理に時間がかかっているだけ」なのか「デッドロック」なのかなど、
そのそれぞれに応じて対応策も変わってきますよね。

どの段階でフリーズしてしまうのか(どこまでは正常動作していたのか)を
ログ出力等で確認されましたか?

編集 削除
Kura  2012-05-10 21:52:58  No: 103284  IP: 192.*.*.*

>VB.NET の場合は隣の掲示板を利用してください。
了解。次回からそうします。よく見ていませんでした。

>とりあえず一般論として:
了解。アドバイスありがとうございます。

>「hoge.Main」「Hoge.Main」と
「hoge.Main」「Hoge.Main」は「test.Main」の間違いです。
 実際のコードからやりたいところだけ抜き出して書き直したとき
 に間違いました。

>何をもって「安全な終了」とするのかは、ケースバイケースですよね。
以前、Excelを制御したときに「VB.NET からExcel を扱う場合は、VB6.0
とは違い全てのCOMオブジェクトを ReleaseComObject する」ということ
を知らずにいたので何度もこのソフトを実行するとメモリ不足のエラーがでました。
一見正常に動作しているように見えても、終了処理が悪くタスクマネージャーで
見るとプロセスに複数のExcel.exeが動いていました。

ウォッチドッグタイマーのためにマルチスレッドを考えていますが、この実装は初めての
ため、また、同じようなことが起きるのではと思い。
アドバイスを求めて投稿しました。

【やりたいこと】
ウォッチドッグタイマー(1分)として下記の処理を考えています。
1.ループ処理をしているメインスレッドからタイマースレッドを起動
  (ループ処理は通常30秒で処理が終了)
2.タイマーが1分になる前にメインスレッドのループ処理が終わればタイマースレッドを終了
  (正常時の処理)
3.タイマーが1分を過ぎるとタイマースレッド側でエラーメッセージを表示し、タイマースレッドを
  終了。さらに、メインスレッドを強制終了
  (異常時の処理:ループ処理がフリーズしているため)

サンプルコードはSystem.Threading.Timeクラスで書きましたが
System.Timers.Timerクラスが使いやすいか?とも考えています。

.Interval = 60*000
.AutoReset = False
.Enabled = True
でメインスレッドからTimer起動

.Enabled = false
でメインスレッドがらTimer停止

ただ、タイムupしたときのタイマースレッドの終了とメインスレッドの強制終了
をタイマースレッド側にどう実装すればよいか?  メインスレッドは何も実装し
なくて良いのか?  がわかりません。
また、timerクラスの使い方が正しいのかもわかりません。

>ログ出力等で確認されましたか?
 ログ出力も追加してフリーズの原因を調べるでが、頻度が、数ヶ月
 に1回のため、並行してウォッチドッグタイマを入れることを考えている
 ところです。

編集 削除
魔界の仮面弁士  2012-05-10 22:24:47  No: 103285  IP: 192.*.*.*

>> VB.NET の場合は隣の掲示板を利用してください。
> 了解。次回からそうします。よく見ていませんでした。

こちらのスレッドは一度閉じて、隣の掲示板に移動(または再質問)していただけないでしょうか。


> ウォッチドッグタイマー(1分)として下記の処理を考えています。

既にいくつかの手順案を回答していますが、あれでは都合が悪かったでしょうか。


> 1.ループ処理をしているメインスレッドからタイマースレッドを起動
>   (ループ処理は通常30秒で処理が終了)

まずは、その設計手法を見直すべきかと思いますよ。

VB6 であれ VB.NET であれ、WinForm なアプリにおいて、UI スレッドが
30 秒もループ待機状態になるというのは、Windows Message 処理の観点からすると
あまり好ましい設計ではありません。3 秒でも長すぎるぐらいです。

ループ処理自体をワーカースレッドに任せるわけにはいかないのでしょうか。

編集 削除
Kura  2012-05-12 11:37:15  No: 103286  IP: 192.*.*.*

>ループ処理自体をワーカースレッドに任せるわけにはいかないのでしょうか。

魔界の仮面弁士さんアドバイスありがとうございました。
この方法で試してみましたが、上手くいきそうです。
一旦これで、この掲示板での質問は閉じます。

また、判らない事があれば、同じタイトル名で「VB.NET掲示板(.NET専用)」
に投稿します。
そのときは、また、アドバイスお願いします。

編集 削除