スレッドタイマとしては以下のページに説明をしましたが、 
⇒スレッドタイマの使い方 
この時のタイマイベントの処理は、単に時刻を表示するだけの処理で時間がほとんど掛からないものでした。 しかし、実際のプログラムではそのようなことはなく、処理時間が結構かかるものが在ると思います。 
そこで今回は、タイマイベントの処理の中に時間が掛かる処理のシミュレーションとして Sleep関数で3秒待たせることにしました。 この関数の呼び出しの前後で時刻表示を入れましたので、何時の時点での処理なのかが分かります。 実際のプログラムは以下の様になります。
スレッドタイマの使い方(イベント処理が時間が掛かる場合)
Imports System.Threading
Imports System.Threading.Thread
Public Class frmTimerTh2
    'スレッドタイマ
    Private mtimer As System.Threading.Timer
    ''' 
    ''' フォームロードイベント
    '''  
    Private Sub frmTimerThMul_Load(sender As Object, e As EventArgs) Handles Me.Load
        'タイマコールバック関数
        Dim timerDelegate As TimerCallback = New TimerCallback(AddressOf TimerEvent)
        '1000msecタイマ生成(コールバック関数の設定)
        mtimer = New Timer(timerDelegate, Nothing, 0, 1000)
    End Sub
    ''' 
    ''' System.Threading.Timer からの呼び出しを処理するメソッド
    '''  
    ''' <param name="state">このデリゲートで呼び出されたメソッドに関連するアプリケーション固有の情報を格納するオブジェクト</param>
    Private Sub TimerEvent(ByVal state As Object)
        'テキストボックスに現在時刻表示
        Dim strDate As String = Now.ToString("hh:mm:ss")
        Invoke(New SetLabelTextDelegate(AddressOf SetLabelText), 
               New Object() {strDate})
        '3秒の待ち
        Invoke(New SetLabelTextDelegate(AddressOf SetLabelText), 
               New Object() {strDate & "⇒Start...5秒の待ち"})
        Sleep(3 * 1000)
        Invoke(New SetLabelTextDelegate(AddressOf SetLabelText), 
               New Object() {strDate & "⇒End.....5秒の待ち"})
    End Sub
    ' ラベル表示デリゲート宣言
    Private Delegate Sub SetLabelTextDelegate(ByVal strText As String)
    ''' 
    ''' ラベル表示
    '''  
    ''' <param name="strText">表示文字列</param>
    Private Sub SetLabelText(ByVal strText As String)
        Me.TextBox1.Text &= strText & vbCrLf
    End Sub
End Class
これを実行させると、以下の様な表示なります。
最初、4個の「Start...5秒の待ち」が続いてその後で「End.....5秒の待ち」が追いかけてくる感じになっています。 
これは、スレッドタイマのイベントの時間間隔が1秒なので、先に発生したイベントを待たずに 次々とイベントが発生させていることが分かります。 つまり、各1秒毎のイベントは別々に実行していることになります。 
3秒待ちの処理が重なって処理されては困ることになります。 そこで、以下のプログラムの様に、イベント処理中のフラグを用いて処理をスキップさせてみました。
スレッドタイマの使い方(イベント処理が時間が掛かる場合:改良版)
Imports System.Threading
Imports System.Threading.Thread
Public Class frmTimerTh2
    'スレッドタイマ
    Private mtimer As System.Threading.Timer
    ''' 
    ''' フォームロードイベント
    '''  
    Private Sub frmTimerThMul_Load(sender As Object, e As EventArgs) Handles Me.Load
        'タイマコールバック関数
        Dim timerDelegate As TimerCallback = New TimerCallback(AddressOf TimerEvent)
        '1000msecタイマ生成(コールバック関数の設定)
        mtimer = New Timer(timerDelegate, Nothing, 0, 1000)
    End Sub
    ''' 
    ''' System.Threading.Timer からの呼び出しを処理するメソッド
    '''  
    ''' <param name="state">このデリゲートで呼び出されたメソッドに関連するアプリケーション固有の情報を格納するオブジェクト</param>
    Private Sub TimerEvent(ByVal state As Object)
        '処理中フラグ
        Static fProcessing As Boolean = False
        '処理中フラグOFFのチェック
        If fProcessing = False Then
            '処理中フラグON
            fProcessing = True
            'テキストボックスに現在時刻表示
            Dim strDate As String = Now.ToString("hh:mm:ss")
            Invoke(New SetLabelTextDelegate(AddressOf SetLabelText), 
                   New Object() {strDate})
            '3秒の待ち
            Invoke(New SetLabelTextDelegate(AddressOf SetLabelText), 
                   New Object() {strDate & "⇒Start...5秒の待ち"})
            Sleep(3 * 1000)
            Invoke(New SetLabelTextDelegate(AddressOf SetLabelText), 
                   New Object() {strDate & "⇒End.....5秒の待ち"})
            '処理中フラグOFF
            fProcessing = False
        End If
    End Sub
    ' ラベル表示デリゲート宣言
    Private Delegate Sub SetLabelTextDelegate(ByVal strText As String)
    ''' 
    ''' ラベル表示
    '''  
    ''' <param name="strText">表示文字列</param>
    Private Sub SetLabelText(ByVal strText As String)
        Me.TextBox1.Text &= strText & vbCrLf
    End Sub
End Class
このプログラムの実行は以下の様になり、イベントの多重呼び出しは無くなりました。
関連する記事
⇒Timerコントロールの使い方 :[Timer,Interval]⇒複数のTimerコントロールの使い方 :[Timer,Interval]
⇒スレッドタイマの使い方 :[System.Threading.Timer,Delegate,Invoke]
PR
 
  
コメント