|
Site |
Cours VB.net |
|
|
|
Multithread. |
|
|
Un Thread c'est quoi?
Le thread représente l'exécution d'un processus en mémoire. Un système multithread tel que Windows offre la capacité d'exécuter en parallèle plusieurs threads et donc plusieurs traitements en simultané.
On peut utiliser la Classe Thread, créer autant de thread que l'on veut, mais il faut gérer un tas de chose et c'est l'horreur.
On peut aussi (Framework 2) utiliser un Thread d'arrière plan (et un seul) qui est très simple d'utilisation. Son intérêts est que lorsqu'on a une tache très longue (très long calcul par exemple), il est possible d'effectuer le calcul long en arrière plan, pendant ce temps, on peut continuer à travailler dans le formulaire (thread principal); quand le thread d'arrière plan est terminé, on affiche les résultats.
Comment ajouter un Thread d'arrière plan?
Il faut aller chercher un composant BackgroundWorker dans la boite à outils et le déposer sur le formulaire, il apparaît en dessous et se nomme par défaut BackgroundWorker1.
La propriété WorkerReportsProgress
donne à notre BackgroundWorker la possibilité de nous informer ou non de son
état d'avancement.
La propriété WorkerSupportsCancellation nous
permet d'autoriser l'annulation de la tâche en cours du BackgroundWorker.
BackGroundWorker1.RunWorkerAsync(Objet) permet de déclencher le thread d'arrière plan.
BackGroundWorker1.DoWork : est l' évènement qui se déclenche lorsque nous faisons appel au BackgroundWorker. C'est cette routine qui tourne en arrière plan.
ProgressChanged : Cet évènement, si la propriété WorkerReportsProgress est activée, se déclenche lorsque nous voulons indiquer que l'état d'avancement du BackgroundWorker change.
RunWorkerCompleted : Une fois le traitement du BackgroundWorker terminé cet événement est déclenché.
Exemple:
Si on clique sur un bouton cela crée un thread d'arrière plan qui effectue un calcul long.
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
'La méthode RunWorkerAsync() du BackgroundWorker déclenche le thread d'arrière plan.
BackgroundWorker1.RunWorkerAsync()
End Sub
'La procédure DoWork contient le code effectué en arrière plan.
Private Sub BackgroundWorker1_DoWork(ByVal sender As System.Object, ByVal e As System.ComponentModel.DoWorkEventArgs) Handles BackgroundWorker1.DoWork
'mes calculs très long
End Sub
'Quand le code d'arrière plan est terminé la procédure RunWorkerCompleted est exécutée.
Private Sub BackgroundWorker1_RunWorkerCompleted(ByVal sender As Object, ByVal e As System.ComponentModel.RunWorkerCompletedEventArgs) Handles BackgroundWorker1.RunWorkerCompleted
' ici, elle affiche un message indiquant de le thread d'arrière plan est terminé.
Label1.Text = "terminé"
End Sub
La méthode RunWorkerAsync peut avoir un paramètre qui sera transmis au thread d'arrière plan.
Mais un seul; ce paramètre étant de type objet, vous pouvez passer un tableau d'objets (string, int, etc...) ou même une structure
Ici dans l'exemple, on a un paramètre numérique, utilisé dans le thread d'arrière plan pour faire un calcul.
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
BackgroundWorker1.RunWorkerAsync(180)
End Sub
Le paramètre , dans DoWork, se retrouve dans e.Argument , comme c'est un Objet, il faut le convertir en Integer pour l'utiliser:
Private Sub BackgroundWorker1_DoWork(ByVal sender As System.Object, ByVal e As System.ComponentModel.DoWorkEventArgs) Handles BackgroundWorker1.DoWork
a=a + Ctype (e.Argument, Integer)
End Sub
Le thread d'arrière plan peut appeler une Sub.
Private Sub BackgroundWorker1_DoWork(ByVal sender As System.Object, ByVal e As System.ComponentModel.DoWorkEventArgs) Handles BackgroundWorker1.DoWork
Calcul()
End Sub
Sub Calcul ()
'Mes calculs
End Sub
(Le thread principal peut lui aussi appeler la routine Calcul.)
Les variables sont accessibles dans le thread d'arrière plan:
'MyVar par exemple qui est Public et déclarée en tête de module.
Public MyVar As Integer = 1
Private Sub BackgroundWorker1_DoWork(ByVal sender As System.Object, ByVal e As System.ComponentModel.DoWorkEventArgs) Handles BackgroundWorker1.DoWork
MyVar=Myvar +1
End Sub
Par contre les objets de l'interface (du thread principal) ne sont pas accessibles dans le thread d'arrière plan:
Cela déclenche une exception si on tente d'y accéder.
État d'avancement:
Si la tâche d'arrière plan est très longue, il peut être intéressant de montrer dans l'interface utilisateur, l'état d'avancement de cette tâche.
Mais on rappelle que la tâche de fond ne peut pas intervenir sur l'interface.
Il faut donc:
Mettre la propriété WorkerReportsProgress de notre BackgroundWorker à True.
Dans le thread d'arrière plan, il faut, a chaque que l'on veut indiquer la progression, appeler la méthode ReportProgress en indiquant l'état d'avancement avec un paramètre.
Private Sub BackgroundWorker1_DoWork()
Dim MyThread As BackgroundWorker = CType(sender, BackgroundWorker)'récupération du thread d'arrière plan
MyThread.ReportProgress(pourcent)'pourcent est un Integer indiquant l'état d'avancement.
End Sub
Noter que c'est au programmeur de créer la logique calculant d'état d'avancement (et donc la valeur de la variable pourcent)
Enfin dans le thread principal, la Sub BackgroundWorker1_ProgressChanged() s'exécute à chaque fois que le thread d'arrière plan le demande et met à jour un index visuel sur l'interface.
Private Sub
BackgroundWorker1_ProgressChanged(
_
ByVal sender As Object,
_
ByVal e As
ProgressChangedEventArgs) _
Handles BackgroundWorker1.ProgressChanged
MyProgressBarr.Value = e.ProgressPercentage
End Sub
Arrêter le thread en cours:
Il suffit de faire dans le thread principal:
BackgroundWorker1.CancelAsync()
Dans le thread d'arrière plan, il faut vérifier si l'arrêt à été demandé:
Dans DoWork on récupère le thread d'arrière plan qui est le sender, on regarde si sa propriété CancellationPending est à True, si oui on met e.cancel à True ce qui arrête le thread d'arrière plan.
Dim MyThread As BackgroundWorker = CType(sender, BackgroundWorker)
If MyThread.CancellationPending Then e.Cancel = True 'ce qui arrête le thread d'arrière plan.
Si on veut tester la demande d'arrêt dans une Sub, il faut envoyer en paramètre à cette sub MyThread et e.
Résultat retourné par le thread d'arrière plan:
Exemple de traitement:
Private Sub BackgroundWorker1_RunWorkerCompleted( _ ByVal sender As Object, _ ByVal e As RunWorkerCompletedEventArgs) _ Handles BackgroundWorker1.RunWorkerCompleted If Not (e.Error Is Nothing) Then lblResult.Text = "Il y a eu une erreur : " + e.Error.Message ElseIf e.Cancelled Then lblResult.Text = "Opération annulée " Else lblResult.Text = "Opération Ok Résultat : " + e.Result.ToString End If End Sub
|
|
|
|
|