none
一定時間ごとに処理を実行したい。でも一定時間経過しても終わらなかったら強制終了したい。 RRS feed

  • 質問

  • フォームアプリケーションをvb2010で作成しています。

    exeを実行してフォームが開いてから5分ごとに処理を実行します。

    実行している処理が20分たっても終わらないときは強制終了して、新しい処理を開始させたいです。

    それまでは5分ごとの処理を実行しないようにしたいです。

    サーバベース・タイマ:System.Timers.Timerクラスで実装可能でしょうか。

    スレッド・タイマ:System.Threading.Timeクラスであればできるのでしょうか。

    サーバベース・タイマだとタイマのインターバルは、その前の実行が終わってからの時間を数えているようでした。なので強制終了できませんでした。

    フォームのloadイベントにどう書いたらスレッド・タイマがちゃんと動作するのかわかりませんでした。

    フォームにはテキストボックスを作りタイマーで実行する処理が開始されるごとに開始時間を書き出したいです。

     

     

    2011年7月22日 7:37

回答

  • VB フォーラムでした。失礼しました。

    スレッドは、外部から、安全に強制終了させる手段がありません。過去にその手の質問がありますので、探してみてください。詳細は見ていませんが、トリッキーな方法で実現出来ないことはないようです。スタートの時間を持っておくのと変わりません。が、私なら、比較するごとに経過時間を計算するより、最初に終了時間を求めます。


    Jitta@わんくま同盟
    2011年7月25日 12:27

すべての返信

  • Timerクラスの使い分けやワーカースレッドについては、こちらが参考になると思います。

    タスクスレッドの起動方法 - とあるコンサルタントのつぶやき - Site Home - MSDN Blogs


    Blog:プログラマーな日々 http://d.hatena.ne.jp/JHashimoto/
    2011年7月22日 10:54
  • exeを実行してフォームが開いてから5分ごとに処理を実行します。

    実行している処理が20分たっても終わらないときは強制終了して、新しい処理を開始させたいです。

    それまでは5分ごとの処理を実行しないようにしたいです。

     5分間隔で処理を実行するタイマーと、その処理の最初でタイムアウトを検出するためのタイマー、2つのタイマーを使えばいいのではないでしょうか。

    サーバベース・タイマだとタイマのインターバルは、その前の実行が終わってからの時間を数えているようでした。なので強制終了できませんでした。

     そうですか?

    Timer クラス
    Elapsed イベントの処理が Interval よりも長びくと、別の ThreadPool スレッドで同じイベントが再発生する場合があります。

     これは、その前の実行が終わるのを待っていないと思います。こんな感じかな。

    /// <summary>プロセスが実行中であることのフラグ。</summary>
    static bool InProcess = false;
    /// <summary>実行時間が長すぎることのフラグ。</summary>
    static bool IsTimeout = false;
    
    private void Process1(object source, ElapsedEventArgs e)
    {
      if (InProcess == true) { return; }
      using (var timeoutTimer = new System.Timers.Timer(20 * 60 * 1000)) {
        try {
          InProcess = true;
          IsTimeout = false;
          timeoutTimer.Elapsed += new ElapsedEventHandler(OnTimeoutEvent);
          TimeoutTimer.Start();
    
          // ここに、実行するべき処理を入れる。
          // ただし、定期的に IsTimeout を参照し、true になっていたら終了する。
          if (IsTimeout == true) { return; }
    
        } finally {
          InProcess = false;
        }
      }
    }
    
    private void OnTimeoutEvent(object source, ElapsedEventArgs e)
    {
      IsTimeout = true;
    }
    

     


    Jitta@わんくま同盟

    2011年7月22日 13:36
  • ありがとうございます。

    Process1はフォームに貼り付けたtimerオブジェクトのTickイベントに書くのでしょうか?

    呼び出し方がわかりません。

    こんな感じで書いてみたら動きました。

    でもフラグを見ないと終了させられないから、スタートの時間を変数で持っているのと変わらない気がします。

     

    Imports System.Timers

    Public Class Form1

        'Dim WebWaitTimeOut As Boolean = False
        Dim Inprocess As Boolean = False
        Dim IsTimeout As Boolean = False

        Delegate Function WriteLineDelegate(ByVal str As String) As Integer

        Public Sub Form1_Load(sender As System.Object, e As System.EventArgs) Handles MyBase.Load

            Dim Timer1 = New System.Timers.Timer(1000)
            AddHandler Timer1.Elapsed, AddressOf OnTimedEvent

            'インターバル(ms)
            Timer1.Interval = 2000

            'タイマーON
            Timer1.Start()

            Me.TextBox1.AppendText("スタート:" & Now.ToString("mm:ss") & vbNewLine)
        End Sub

        Private Sub OnTimedEvent(source As Object, e As ElapsedEventArgs)


            Dim threadName As String = System.Threading.Thread.CurrentThread.Name
            Dim dlg As New WriteLineDelegate(AddressOf WriteLine)
            Dim ar As IAsyncResult


            If Inprocess = True Then
                ar = Me.BeginInvoke(dlg, New Object() {"かぶった" & Now.ToString("mm:ss") & vbNewLine})
                Exit Sub
            End If

            Using timeoutTimer As New System.Timers.Timer(1 * 1000)
                Try
                    Inprocess = True
                    IsTimeout = False

                    AddHandler timeoutTimer.Elapsed, AddressOf OnTimeoutEvent

                    timeoutTimer.Start()

                    If IsTimeout = True Then
                        ar = Me.BeginInvoke(dlg, New Object() {"強制終了" & Now.ToString("mm:ss") & vbNewLine})
                        Exit Sub
                    End If

                    ar = Me.BeginInvoke(dlg, New Object() {"メイン" & Now.ToString("mm:ss") & vbNewLine})

                    System.Threading.Thread.Sleep(3000)

                    If IsTimeout = True Then
                        ar = Me.BeginInvoke(dlg, New Object() {"強制終了" & Now.ToString("mm:ss") & vbNewLine})
                        Exit Sub
                    End If


                Catch ex As Exception

                Finally
                    Inprocess = False

                End Try


            End Using


        End Sub



        Private Sub OnTimeoutEvent(source As Object, e As ElapsedEventArgs)

            IsTimeout = True

            Dim threadName As String = System.Threading.Thread.CurrentThread.Name
            Dim dlg As New WriteLineDelegate(AddressOf WriteLine)
            Dim ar As IAsyncResult = Me.BeginInvoke(dlg, New Object() {"タイムアウト" & Now.ToString("mm:ss") & vbNewLine})

        End Sub

        Private Function WriteLine(ByVal str As String) As Integer


            TextBox1.AppendText(str)

            Return TextBox1.Lines.Length

        End Function

    End Class

    2011年7月25日 1:38
  • ありがとうございます。

    参考になりました。

    2011年7月25日 1:39
  • VB フォーラムでした。失礼しました。

    スレッドは、外部から、安全に強制終了させる手段がありません。過去にその手の質問がありますので、探してみてください。詳細は見ていませんが、トリッキーな方法で実現出来ないことはないようです。スタートの時間を持っておくのと変わりません。が、私なら、比較するごとに経過時間を計算するより、最初に終了時間を求めます。


    Jitta@わんくま同盟
    2011年7月25日 12:27
  •  5分間隔で処理を実行するタイマーと、その処理の最初でタイムアウトを検出するためのタイマー、2つのタイマーを使えばいいのではないでしょうか。

    今更ですが念のため。

    タイムアウトの制御に別途同じ仕組みのタイマーを使用するのはちょっと怪しい気がします。スレッドプールを使用するタイマーの場合、CPUに空きができないと処理が開始されない可能性が高いですので、環境によってはタイムアウトさせたい処理が実行中のために、タイムアウトチェック用の処理が起動しない、というようなことが起こりそうです。

    まあ現実には、シングルCPU環境でCPU負荷が高い処理をずっと実行している場合などに限られるでしょうから、そんなに起こらないとは思いますが、考え方としてはちょっと注意が必要に思います。

    2011年7月28日 7:50
  • スレッドプールを使用するタイマーの場合、CPUに空きができないと処理が開始されない可能性が高いですので、環境によってはタイムアウトさせたい処理が実行中のために、タイムアウトチェック用の処理が起動しない、というようなことが起こりそうです。

     デリゲートの非同期実行が、「対象メソッドは、スレッド プールのスレッドで呼び出されます。」と書いてあるのですが、実際にはタスクで実行されているので、このタイマーもそうなんだろうと思っていたのですが、スレッドで実行されていました。


    Jitta@わんくま同盟
    2011年8月1日 12:06