Imports System.Threading
Public MustInherit Class ClsBaseThread
    Implements IDisposable
#Region "Attributs partagés"
    ''' -----------------------------------------------------------------------------
    ''' <summary>
    ''' Attribut de classe, à tester pour le StopAllThread
    ''' </summary>
    ''' -----------------------------------------------------------------------------
    Protected Friend Shared msCanRun As Boolean
    ''' -----------------------------------------------------------------------------
    ''' <summary>
    ''' Attribut de la classe, si true, arrêt rapide des thread préférable
    ''' </summary>
    ''' -----------------------------------------------------------------------------
    Protected Friend Shared msFinalize As Boolean
    ''' -----------------------------------------------------------------------------
    ''' <summary>
    ''' Liste des threads en cours d'execution
    ''' </summary>
    ''' -----------------------------------------------------------------------------
    Protected Friend Shared msLstThreads As ArrayList
#End Region
#Region "Attributs protégés"
    ''' -----------------------------------------------------------------------------
    ''' <summary>
    ''' Attribut d'objet à tester pour le StopThread
    ''' </summary>
    ''' -----------------------------------------------------------------------------
    Protected Friend mCanRun As Boolean = True
    ''' -----------------------------------------------------------------------------
    ''' <summary>
    ''' Attribut d'objet true si le thread fonctionne (ne pas modifier, modification automatique)
    ''' </summary>
    ''' -----------------------------------------------------------------------------
    Protected Friend mThreadRun As Boolean = False
    ''' -----------------------------------------------------------------------------
    ''' <summary>
    ''' Si ture, indique que l'arrêt du thread doit être rapide (génération d'un ThreadAbortException toutes les 2 secondes)
    ''' </summary>
    ''' -----------------------------------------------------------------------------
    Protected Friend mFinalize As Boolean = False
#End Region
    Private mThread As Thread
#Region "Constructeurs"
    ''' -----------------------------------------------------------------------------
    ''' <summary>
    ''' Initialise les attributs shared
    ''' </summary>
    ''' -----------------------------------------------------------------------------
    Shared Sub New()
        msFinalize = False
        msCanRun = True
        msLstThreads = New ArrayList
    End Sub
    ''' -----------------------------------------------------------------------------
    ''' <summary>
    ''' Constructeur de la classe+execution immédiate du thread
    ''' </summary>
    ''' <param name="pName">Optionnel, nom du thread</param>
    ''' -----------------------------------------------------------------------------
    Protected Friend Sub New(Optional ByVal pName As String = "")
#If DEBUG Then
        Debug.WriteLine("Démarrage du thread : " + pName)
#End If
        mThread = New Thread(AddressOf SubThread)
        mThread.Name = pName
        mThread.Start()
    End Sub
#End Region
    ''' -----------------------------------------------------------------------------
    ''' <summary>
    ''' Retourne le nom du thread actuel
    ''' </summary>
    ''' -----------------------------------------------------------------------------
    Public ReadOnly Property Name() As String
        Get
            Return mThread.Name
        End Get
    End Property
    ''' -----------------------------------------------------------------------------
    ''' <summary>
    ''' Retourne ture si le thread est encode en fonctionnement.
    ''' </summary>
    ''' -----------------------------------------------------------------------------
    Public ReadOnly Property ThreadRun() As Boolean
        Get
            Return mThreadRun
        End Get
    End Property
#Region "Procédure concernants tous les threads"
    ''' -----------------------------------------------------------------------------
    ''' <summary>
    ''' Arrête tous les threads actifs
    ''' </summary>
    ''' <param name="pWait">si true, attent que tous les threads soient arrêtés</param>
    ''' <param name="pHurry">Demande aux thread de s'arrêter rapidement</param>
    ''' -----------------------------------------------------------------------------
    Friend Shared Sub StopAllThread(Optional ByVal pWait As Boolean = False, Optional ByVal pHurry As Boolean = False)
        msCanRun = False
        If pHurry Then msFinalize = True
        Do While (pWait And msLstThreads.Count > 0) : Thread.Sleep(0) : Loop
    End Sub
    ''' -----------------------------------------------------------------------------
    ''' <summary>
    ''' Retourne le nombre de thread actuellement en fonctionnement
    ''' </summary>
    ''' <returns></returns>
    ''' -----------------------------------------------------------------------------
    Friend Shared Function NbThreadRun() As Integer
        Return msLstThreads.Count
    End Function
#End Region
    ''' -----------------------------------------------------------------------------
    ''' <summary>
    ''' Arrête le thread courant
    ''' </summary>
    ''' <param name="pWait">si true, attent que le thread soit arrêté</param>
    ''' -----------------------------------------------------------------------------
    Friend Sub StopThread(Optional ByVal pWait As Boolean = False)
        mCanRun = False
        Do While (pWait And mThreadRun) : Thread.Sleep(0) : Loop
    End Sub
#Region "méthodes à substituer"
    ''' -----------------------------------------------------------------------------
    ''' <summary>
    ''' Méthode du thread
    ''' </summary>
    ''' -----------------------------------------------------------------------------
    Protected MustOverride Sub Run()
    ''' -----------------------------------------------------------------------------
    ''' <summary>
    ''' Appelé en cas d'erreur dans le thread
    ''' </summary>
    ''' <param name="pEx">Exception interceptée</param>
    ''' -----------------------------------------------------------------------------
    Protected MustOverride Sub SubError(ByRef pEx As Exception)
    ''' -----------------------------------------------------------------------------
    ''' <summary>
    ''' Appelé pour terminer le thread
    ''' </summary>
    ''' -----------------------------------------------------------------------------
    Protected MustOverride Sub EndThread()
#End Region
    ''' -----------------------------------------------------------------------------
    ''' <summary>
    ''' Méthode de gestion du thread
    ''' </summary>
    ''' -----------------------------------------------------------------------------
    Private Sub SubThread()
        Try
            mThreadRun = True
            Me.msLstThreads.Add(Me)
            'msNbThread += 1
            Run()
        Catch ex As Exception
            Try
                SubError(ex)
            Catch ex1 As Exception
#If DEBUG Then
                Debug.WriteLine("Erreur dans la procédure de gestion des erreurs du thread " + mThread.Name + Environment.NewLine + ex.ToString + Environment.NewLine + "Erreur générée :" + Environment.NewLine + ex1.ToString)
#End If
            End Try
        Finally
            Try
                EndThread()
            Catch ex As Exception
                Try
                    SubError(ex)
                Catch ex1 As Exception
#If DEBUG Then
                    Debug.WriteLine("Erreur dans la procédure de gestion des erreurs du thread " + mThread.Name + Environment.NewLine + ex.ToString + Environment.NewLine + "Erreur générée :" + Environment.NewLine + ex1.ToString)
#End If
                End Try
            End Try
            Me.msLstThreads.Remove(Me)
            mThreadRun = False
            System.GC.Collect()
            System.GC.WaitForPendingFinalizers()
        End Try
    End Sub
    ''' -----------------------------------------------------------------------------
    ''' <summary>
    ''' Met le thread en pause pendant pMilisec millisecondes
    ''' </summary>
    ''' <param name="pMilisec">pause en ms</param>
    ''' -----------------------------------------------------------------------------
    Protected Friend Sub Sleep(ByVal pMilisec As Integer)
        mThread.Sleep(pMilisec)
    End Sub
    ''' -----------------------------------------------------------------------------
    ''' <summary>
    ''' Retourne une String représentant l'état de l'objet
    ''' </summary>
    ''' <returns></returns>
    ''' -----------------------------------------------------------------------------
    Public Overrides Function ToString() As String
        Dim lStr As String = "ClsBaseThread : "
        lStr += " Attributs shared {"
        lStr += "msCanRun=" + CStr(msCanRun)
        lStr += ",msLstThreads.Count=" + CStr(msLstThreads.Count)
        lStr += ",msFinalize=" + CStr(msFinalize)
        lStr += "} Attributs protected {"
        lStr += "mCanRun=" + CStr(mCanRun)
        lStr += ",mThreadRun=" + CStr(mThreadRun)
        lStr += ",msFinalize=" + CStr(msFinalize)
        lStr += "}"
#If DEBUG Then
        lStr += "Debug Mode"
#Else
        lStr += "Release Mode"
#End If
        Return lStr
    End Function
    ''' -----------------------------------------------------------------------------
    ''' <summary>
    ''' Décharge l'objet immédiatement
    ''' </summary>
    ''' -----------------------------------------------------------------------------
    Friend Sub Dispose() Implements System.IDisposable.Dispose
        mCanRun = False
        mFinalize = True
    End Sub
    ''' -----------------------------------------------------------------------------
    ''' <summary>
    ''' destructeur
    ''' </summary>
    ''' -----------------------------------------------------------------------------
    Protected Overrides Sub Finalize()
        mCanRun = False
        mFinalize = True
        Do While mThreadRun
            If mThread.Join(2000) = False Then
                mThread.Abort()
            End If
        Loop
        MyBase.Finalize()
    End Sub
End Class
