忍者ブログ

VB.NET-TIPS などプログラミングについて

VB.NETのTIPS(小技集)を中心に、Javascript その他のプログラミングについて少し役に立つ情報を発信します。いわゆる個人的な忘備録ですが、みなさんのお役に立てれば幸いです。

スレッドを停止させる方法について

スレッドを以下のプログラムの様に作成し開始させると Main 関数は先に終了しますが、スレッドは約5秒後にしか終了しないため、 全体のプログラムの実行はスレッドが終了するまで続きます。
コンソールへの表示からも分かりますが「Main終了」が表示された後で「...スレッド」が5回表示されます。

これは何もおかしいことでは無く、プログラムは属する全てのスレッドが終了するまでは終われないのです。
Main 関数も1個のスレッド(メインスレッド)として実行されるのでが処理的に先に終わってしまいます。
しかし、別のスレッドとして起動された ThreadProc 関数が残っているので、このスレッドが終了するまで プログラムは終了しません。

スレッドの実行プログラム

Imports System
Imports System.Threading

Module ThreadStop

    'メイン関数(エントリーポイント)
    Sub Main()
        'スレッド生成
        Dim pThread As Thread = New Thread(AddressOf ThreadProc)

        Console.WriteLine("スレッド開始")
        'スレッド開始
        pThread.Start()

        Console.WriteLine("Main終了")
    End Sub

    'スレッド関数
    Sub ThreadProc()
        For i As Integer = 1 To 5
            Threading.Thread.Sleep(1000)
            Console.WriteLine("...スレッド")
        Next
    End Sub

End Module

取敢えず、実行結果がコンソールに以下の様に表示されます。

スレッド開始
Main終了
...スレッド
...スレッド
...スレッド
...スレッド
...スレッド

それでは Main 関数の中でスレッドの終了を待つにはどうすればいいのでしょうか。 そのために Thread クラスには Join メソッドがあります。 この Join をスレッドの実行側で呼出せば、呼び出し側の処理がブロックされます。
Join 実行した場合に制御が戻ってこない)
先ほどの例に Join を追加した例を示します。

スレッドの実行を待つプログラム

Imports System
Imports System.Threading

Module ThreadStop

    'メイン関数(エントリーポイント)
    Sub Main()
        'スレッド生成
        Dim pThread As Thread = New Thread(AddressOf ThreadProc)

        Console.WriteLine("スレッド開始")
        'スレッド開始
        pThread.Start()

        'スレッド終了待機
        pThread.Join()
        Console.WriteLine("Main終了")
    End Sub

    'スレッド関数
    Sub ThreadProc()
        For i As Integer = 1 To 5
            Threading.Thread.Sleep(1000)
            Console.WriteLine("...スレッド")
        Next
    End Sub

End Module

実行結果は以下の様に「Main終了」が最後に表示されます。

スレッド開始
...スレッド
...スレッド
...スレッド
...スレッド
...スレッド
Main終了

Join の替わりにスレッドが生きているかどうかのフラグを見て以下の様にしても同じです。

スレッドの実行を待つプログラム2

Imports System
Imports System.Threading

Module ThreadStop

    'メイン関数(エントリーポイント)
    Sub Main()
        'スレッド生成
        Dim pThread As Thread = New Thread(AddressOf ThreadProc)

        Console.WriteLine("スレッド開始")
        'スレッド開始
        pThread.Start()

        'スレッド終了待機
        While pThread.IsAlive = True
            Threading.Thread.Sleep(10)
        End While
        Console.WriteLine("Main終了")
    End Sub

    'スレッド関数
    Sub ThreadProc()
        For i As Integer = 1 To 5
            Threading.Thread.Sleep(1000)
            Console.WriteLine("...スレッド")
        Next
    End Sub

End Module


それでは標題にある様にスレッドを停止させる方法についてですが、 Abort メソッドを使用します。 スレッドの中で非常に時間の掛かる処理を行わせて、途中で停止させる例を以下に示します。

スレッドの実行を途中で停止させるプログラム

Imports System
Imports System.Threading

Module ThreadStop

    'メイン関数(エントリーポイント)
    Sub Main()
        'スレッド生成
        Dim pThread As Thread = New Thread(AddressOf ThreadProc)

        Console.WriteLine("スレッド開始")
        'スレッド開始
        pThread.Start()

        '10秒待つ
        Threading.Thread.Sleep(10000)

        'スレッド停止
        pThread.Abort()

        'スレッド終了待機
        pThread.Join()
        Console.WriteLine("Main終了")
    End Sub

    'スレッド関数
    Sub ThreadProc()
        For i As Integer = 1 To 1000    '時間の掛かる処理
            Threading.Thread.Sleep(1000)
            Console.WriteLine("...スレッド")
        Next
    End Sub

End Module

実行結果は以下の様になり「...スレッド」が10回表示されてからスレッドが停止していることが分かります。

スレッド開始
...スレッド
...スレッド
...スレッド
...スレッド
...スレッド
...スレッド
...スレッド
...スレッド
...スレッド
...スレッド
Main終了

スレッドをいきなり終了させるのも怖いので、スレッドに対してフラグで指示を行い、 スレッドの中でフラグを見て終了させるようにしてみます。
尚、スレッドを含む処理をクラスの中に入れ込んで、 その中で開始メソッドや停止メソッドを作成します。

スレッドの実行を途中で停止させるクラスの導入

Imports System
Imports System.Threading

Module ThreadStop

    'メイン関数(エントリーポイント)
    Sub Main()
        'スレッド用クラスの生成
        Dim pclsThread As New clsThread

        'スレッド開始
        pclsThread.Start()
        Console.WriteLine("スレッド開始")
        '10秒待つ
        Threading.Thread.Sleep(10000)

        'スレッド停止
        pclsThread.Abort()

        Console.WriteLine("Main終了")
    End Sub

    'スレッド用クラス
    Class clsThread
        'スレッド
        Private mThread As Thread = Nothing
        'スレッド停止フラグ
        Private mblnStop As Boolean = False

        '開始メソッド
        Sub Start()
            mThread = New Thread(AddressOf ThreadProc)
            'スレッド開始
            mThread.Start()
        End Sub

        '停止メソッド
        Sub Abort()
            'スレッド停止フラグON
            mblnStop = True
            'スレッド停止を待つ
            mThread.Join()
        End Sub

        'スレッド関数
        Private Sub ThreadProc()
            For i As Integer = 1 To 1000
                If Me.mblnStop = True Then
                    'スレッド停止フラグONならば処理中断
                    Exit For
                End If
                Threading.Thread.Sleep(1000)
                Console.WriteLine("...スレッド")
            Next
        End Sub

    End Class

End Module
PR

コメント

コメントを書く