IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

VB.NET Discussion :

Explication Multi Thread [Débutant]


Sujet :

VB.NET

  1. #1
    Membre habitué
    Profil pro
    Inscrit en
    Juin 2011
    Messages
    9
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2011
    Messages : 9
    Par défaut Explication Multi Thread
    Bonjour ! Je suis tout nouveau sur ce forum car je viens de me mettre au VB.net mais malheureusement j'ai déjà un problème...
    J'ai crée une connexion socket, avec une fenêtre ou se trouve un label qui se modifie en fonction de la connexion( "En ligne" si connecté // "Non connecté" si non connecté )

    Opération inter-threads non valide : le contrôle 'Label1' a fait l'objet d'un accès à partir d'un thread autre que celui sur lequel il a été créé.
    Après des recherches sur ce problème je comprend qu'il faut que je gère le multi thread, certain parle de Backgroundworker et d'autre de
    InvokeRequired - Invoke

    Je voudrais savoir quel est le meilleur moyen de gérer ça ?
    J'ai cru comprendre que Backgrounworker était plus pour les thread lourd...
    Je comptais donc me tourné vers InvokeRequired et invoke mais je ne sais pas comment l'utiliser ?

    Quelqu'un aurait-il un exemple simple de l'utilisation ?
    J'ai compris que InvokeRequired testé si on se trouvé dans le bon thread, mais c'est invoke qui me pause problème...

    Désoler je me suis un peu lancé a l'aveuglette dans VB.net...
    Merci d'avance de votre aide, veuillez m'excusez de mon niveau...

  2. #2
    Membre Expert

    Homme Profil pro
    Développeur .NET
    Inscrit en
    Novembre 2010
    Messages
    2 067
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Développeur .NET

    Informations forums :
    Inscription : Novembre 2010
    Messages : 2 067
    Par défaut
    bonjour,
    essaye de renvoyer une string plutôt et tu l'affectera a ton label sinon tu risques de devoir utiliser l'invoke pour affecter directement ton label

  3. #3
    Membre expérimenté
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Novembre 2010
    Messages
    151
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 38
    Localisation : France, Loire Atlantique (Pays de la Loire)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : High Tech - Multimédia et Internet

    Informations forums :
    Inscription : Novembre 2010
    Messages : 151
    Par défaut
    Dans un BackGroundWorker tu ne peux (à ma connaissance) pas modifier les élements créés dans d'autre Thread. Pour faire cela, il faut le faire dans l'évenement RunWorkerCompleted. Tu es donc obligé de passer le résultat de ta connexion, dans la variable Result (du DoWorkEventArgs). Tu peux stocker dans cette variable n'importe quel type (ou du moins un grand nombre) de données

    Quant aux InvokeRequired, je passe mon tour, je n'en ai jamais utilisé, mais interessé de savoir à quoi ils peuvent servir.

    Et utiliser BackGroundWorker pour des threads lourds n'est pas forcement obligatoire, je l'utilise aussi pour des threads légers comme affichage de la date et l'heure sur une Form sans perturber le fonctionnement (Timer+BGW)

    EDIT : Petit exemple de BGW :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    Private Sub bgwDateHeure_DoWork(ByVal sender As System.Object, ByVal e As System.ComponentModel.DoWorkEventArgs) Handles bgwDateHeure.DoWork
            e.Result = MaJDH()
        End Sub
     
        Private Sub bgwDateHeure_RunWorkerCompleted(ByVal sender As Object, ByVal e As System.ComponentModel.RunWorkerCompletedEventArgs) Handles bgwDateHeure.RunWorkerCompleted
            Dim al As ArrayList = e.Result
            Date_.Text = al(0)
            Heure_.Text = al(1)
        End Sub
     
        Private Function MaJDH() As ArrayList
            MaJDH = New ArrayList
            Dim d As Date = Now 'On récupère l'heure courante
     
            ' On met à jour les affichages
            MaJDH.Add(d.Date)
            MaJDH.Add(d.ToString("HH:mm:ss"))
        End Function
    Et ce code est appelé toutes les 1000ms par un Timer

  4. #4
    Membre habitué
    Profil pro
    Inscrit en
    Juin 2011
    Messages
    9
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2011
    Messages : 9
    Par défaut
    Tout d'abord un grand merci pour l'attention que vous m'accordez, je ne pensez pas obtenir de réponse a cette heure ci...
    Un grand merci !

    Citation Envoyé par youtpout978 Voir le message
    bonjour,
    essaye de renvoyer une string plutôt et tu l'affectera a ton label sinon tu risques de devoir utiliser l'invoke pour affecter directement ton label
    Je ne comprend pas ce que tu veut dire... Voici le code qui traite le label

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
     
        Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
            Dim ipAddr As System.Net.IPAddress
     
            SocketServer = New Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp)
            ipAddr = IPAddress.Parse("127.0.0.1")
            SocketServer.Bind(New IPEndPoint(ipAddr, 80))
            SocketServer.Listen(1)
            Me.SocketServer.BeginAccept(AddressOf connexionCallback, Me.SocketServer)
        End Sub
     
        Private Sub connexionCallback(ByVal asyncResult As IAsyncResult)
            SocketServer = SocketServer.EndAccept(asyncResult)
            Me.Label1.Text = "Le client est connecté"
        End Sub
    @matll
    J'ai cru comprendre d'après la doc de Microsoft que c'est un événement qui renvoi une donné si le processus est fini ?
    Je doit faire une boucle avec ou il y a une utilisation spéciale ?

    Euh...Maintenant un autre problème me vient...J’établis une connexion socket, si elle est réussi je change le label, mais ce n'est pas pour autant que je veut fermer la connexion, donc le processus ne s’arrête jamais... si ?

  5. #5
    Membre Expert

    Homme Profil pro
    Développeur .NET
    Inscrit en
    Novembre 2010
    Messages
    2 067
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Développeur .NET

    Informations forums :
    Inscription : Novembre 2010
    Messages : 2 067
    Par défaut
    si ta deux état tu peux déclarer un booléen dans ton application
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
    Private Sub connexionCallback(ByVal asyncResult As IAsyncResult)
            SocketServer = SocketServer.EndAccept(asyncResult)
            Me.boolConnect =true
        End Sub
    et tu utlise un timer qui toutes les secondes vérifiera l'état de ton boolean s'il est a true alors tu mettras
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    Me.Label1.Text = "Le client est connecté"
    tu mettras bien ça dans l'événement tick du timer

  6. #6
    Membre habitué
    Profil pro
    Inscrit en
    Juin 2011
    Messages
    9
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2011
    Messages : 9
    Par défaut
    Oui ceci devrait être mieux au niveau de la gestion des labels ( j'étais resté simple pour les tests.. ) mais...( Je n'ai pas encore testé ) le problème de multi thread restera...non ?

    EDIT :
    Après test, voila le code

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    Private Sub connexionCallback(ByVal asyncResult As IAsyncResult)
            Dim SocketConnect As Boolean
     
            SocketServer = SocketServer.EndAccept(asyncResult)
            SocketConnect = True
        End Sub
     
        Private Sub Timer1_Tick(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Timer1.Tick
            If SocketConnect = True Then
                Me.Label1.Text = "Le client est connecté"
            End If
        End Sub
    Plus d'erreur =D Mais plus de mouvement...^^
    Le client capte bien la connexion mais le serveur non...
    Et tant que j'y pense, je ne test pas la connexion toute les 1000ms mais je vérifie si la connexion a bien était établie une fois..

    connexionCallback est simplement appelé une fois la connexion établie, mais elle n'est pas testé...Une idée ?

  7. #7
    Membre Expert

    Homme Profil pro
    Développeur .NET
    Inscrit en
    Novembre 2010
    Messages
    2 067
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Développeur .NET

    Informations forums :
    Inscription : Novembre 2010
    Messages : 2 067
    Par défaut
    Je ne pourrai pas t'aider plus au niveau des sockets je ne les ai jamais utilisé.
    Le faite de ne pas directement renseigné ton label dans ton thread permet d'éviter les erreurs d'accès multi-thread
    http://msdn.microsoft.com/fr-fr/library/ms171728.aspx

  8. #8
    Expert éminent Avatar de Pol63
    Homme Profil pro
    .NET / SQL SERVER
    Inscrit en
    Avril 2007
    Messages
    14 204
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 44
    Localisation : France, Puy de Dôme (Auvergne)

    Informations professionnelles :
    Activité : .NET / SQL SERVER

    Informations forums :
    Inscription : Avril 2007
    Messages : 14 204
    Par défaut
    il n'y a pas énormément de différence entre un thread et un backgroundworker

    il est impossible de modifier un control depuis un thread autre que celui qui l'a créé, tous les controles sont en général créés sur le thread principal
    pour les variables non controles pas de soucis, hormis un accès concurrentiel qui peut faire planter
    par exemple si un thread fait un for each sur une collection, et qu'un autre thread fait .add sur la même collection, celui qui fait le for each va planter car la collection a changé
    pour éviter ce problème on utilise des verrous pour rendre le tout thread safe (= peut etre appelé par x thread en même sans planter) ... plus d'explications si nécessaires mais ce n'est pas le sujet pour l'instant ^^

    pour le le backgroundworker voir ici : http://www.developpez.net/forums/d10...m/#post5757425
    il y a 2 évènement qui sont relayés par le thread principal, qui permettent donc de lui envoyer des données qu'il mettre dans les controles

    le backgroundworker est une encapsulation d'un thread
    depuis un thread classique (system.threading.thread) la méthode est en effet invokerequired/invoke/begininvoke
    tous les controles ont un booléen InvoqueRequired, cette propriété retourne true, si quand on demande sa valeur on est sur un autre thread que le thread qui a créé le controle
    s'il vaut true ca veut donc dire qu'on ne peut pas modifier le controle d'ici
    uncontrol.invoke sert à demander au controle de mettre sur la pile du thread principal l'appel d'un délégué (pointeur vers une sub)
    .begininvoke fait la même chose mais en asynchrone, ca veut dire qu'on demande l'exécution mais en attend pas la fin, le thread continue immédiatement (alors qu'avec .invoke on attend la fin de l'exécution de la sub pointé pour continuer)

    2 méthodes simples

    private delegate sub DEmajtextbox(letextbox as textbox, lestring as string)

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    sub majtextbox(letextbox as textbox, lestring as string)
      if letextbox.invokerequired then
         dim d as new DEmajtextbox(addressof majtextbox)
         letextbox.invoke(d,letextbox, lestring)
         exit sub
      end if
     
      letextbox.text = lestring
    end sub
    ici on a une méthode générique permettant de modifier le text d'un textbox, c'est la sub qui s'occupe de vérifier si on est sur le bon thread au moment de son appel, si invokerequired on créé un nouveau délégué et on l'appel puis on sort avec exit sub
    le délégué va rappeler la même sub, mais sur le bon thread donc ne passant pas dans le if (si on est directement sur le bon thread ca modifie directement le texte aussi)



    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    sub traitement ' sur un autre thread
       'traitement
       if me.invokerequired then me.invoke(new action(of textbox,string)(addressof MajTextbox(letextbox, lestring))
    end sub
    en théorie ca serait if letextbox.invokerequired, mais vu que le form et le textbox sont censé être sur le même thread il arrive couramment qu'on fasse ca sur me

    en plus là on sait qu'on est pas sur le bon thread, donc on pourrait éviter de tester invokerequired

    je vous ai aussi mis la syntaxe simple du délégué faisable depuis vs 2008
    depuis vs 2010 on peut même faire des sub anonymes :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    letextbox.invoke(new Action (Sub() letextbox.text = lestring))
    après dans quel cas utiliser l'un ou l'autre, c'est selon les gouts, bienque pour un traitement lourd ou une boucle infinie (communication port ou réseau) j'aurais tendance à utiliser un thread, mais ca n'apporte rien de plus
    Cours complets, tutos et autres FAQ ici : C# - VB.NET

  9. #9
    Membre habitué
    Profil pro
    Inscrit en
    Juin 2011
    Messages
    9
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2011
    Messages : 9
    Par défaut
    Je pense avoir compris mais il y a un petite erreur
    Seulement l'erreur me parle de "DEmajlabel"

    Erreur 1 Type 'DEmajlabel' non défini. Line 43 26 Socket serveur

    Donc je peut générer la classe mais du cou des erreurs apparaisse dans les paramètre

    Erreur 1 Impossible de convertir l'expression 'AddressOf' en 'Object', car 'Object' n'est pas un type délégué. Line 43 37 Socket serveur

    Erreur 2 Impossible de convertir une valeur de type 'WindowsApplication1.DEmajlabel' en 'System.Delegate'. Line 44 27 Socket serveur

    Vous pouvez me donner un dernier coup de pouce ?


    C'est bon sa marche ! =D Je vous remercie énormément ! =D
    Un gros merci a vous tous !

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Tri multi-threadé
    Par Tifauv' dans le forum C
    Réponses: 8
    Dernier message: 28/06/2007, 09h00
  2. Réponses: 2
    Dernier message: 15/05/2004, 18h33
  3. Réponses: 16
    Dernier message: 30/01/2004, 11h05
  4. [VB6][active x] faire du multi-thread avec vb
    Par pecheur dans le forum VB 6 et antérieur
    Réponses: 9
    Dernier message: 20/05/2003, 12h01
  5. [Kylix] exception qtinft.dll et multi-threading
    Par leclaudio25 dans le forum EDI
    Réponses: 3
    Dernier message: 27/03/2003, 18h09

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo