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

Windows Forms Discussion :

[VB.net] Question simple sur les Timers


Sujet :

Windows Forms

  1. #1
    Membre du Club
    Profil pro
    Inscrit en
    Novembre 2004
    Messages
    100
    Détails du profil
    Informations personnelles :
    Localisation : Belgique

    Informations forums :
    Inscription : Novembre 2004
    Messages : 100
    Points : 65
    Points
    65
    Par défaut [VB.net] Question simple sur les Timers
    Salut à tous,

    Dans une de mes applis, je dois effectuer des vérifications constamment et effectuer des actions en conséquence. J'utilise plusieurs Timers et dans mon étape débogage, je me suis demandé si un Timer passe en priorité l'exécution complète de son code ou son Intervale ?

    En d'autres mots, si j'ai beaucoup de code dans un timer qui a un intervale de 100ms, est-ce qu'il va prendre le temps de finir ce qu'il a commencer ou si ça lui prend plus de temps, il va sans cesse répéter les premières lignes de code et ignorer le reste ?

    En plus clair,


    non je rigole...

    Quelqu'un a une idée ?

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

    Informations professionnelles :
    Activité : .NET / SQL SERVER

    Informations forums :
    Inscription : Avril 2007
    Messages : 14 177
    Points : 25 119
    Points
    25 119
    Par défaut
    ca serait quand meme grave si ca s'arretait au bout de quelques lignes, et personne ne développerait sous .net !!

    prenons un timer à 2 secondes et 3 secondes de traitement
    S0 le timer se déclenche, le code commence à s'executer
    S2 au bout de 2 secondes, le timer se redéclenche alors que l'evenement n'est pas fini, l'evenement est mis en attente sur la pile des appels, le code d'origine continue de s'executer
    S3 une seconde plus tard, le premier appel se termine, le programme reprend la main et regarde sur la pile des appels s'il y a quelque chose à faire, en l'occurrence oui, appeler la sub de l'évènement
    S3 la sub redémarre donc pour 3 secondes de traitement (sans attendre 2 secondes)
    S4 le timer se redéclenche, comme à S2, l'appel se met sur la pile
    etc...

    si on continue on peut imaginer que le timer allant toujours plus vite que son traitement, il va y avoir des centaines d'appels dans la pile
    fait "rassurant", ce n'est pas le cas
    apparemment le timer ne laisse pas plus de 2 appels sur la pile, sinon ca finirait par déborder et génerer un stackoverflowexception


    le timer windows forms est sur le thread principal
    sur un thread le code ne s'execute qu'à un endroit à la fois
    quand 3 evènement se produisent en meme temps, ils sont mis sur une pile, et le programme dépile pour executer les sub liés aux évènements

    dans l'exemple que je donne, le programme sera fortement ralenti, car pendant que du code s'execute l'interface est figée (vu que le code ne s'execute qu'à un endroit à la fois, sur un traitement long, l'interface utilisateur ne peut meme pas se redessiner)
    en tout cas il n'y a plus de temporisation, l'appel se faisant directement après la fin de l'execution

    certains mettent timer.stop au début de la sub et timer.start dans le finally d'un try catch
    m'enfin pour des traitements lourds, il vaut mieux faire un thread séparé, plus performant, et ne figeant pas l'interface utilisateur (voir backgroundworker par exemple)

  3. #3
    Membre régulier
    Homme Profil pro
    Architecte technique
    Inscrit en
    Octobre 2008
    Messages
    83
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52
    Localisation : France, Morbihan (Bretagne)

    Informations professionnelles :
    Activité : Architecte technique
    Secteur : Industrie

    Informations forums :
    Inscription : Octobre 2008
    Messages : 83
    Points : 96
    Points
    96
    Par défaut
    Justement je rebondis sur ce sujet.
    J'utilise aussi les timers pour scruter des évenements extérieur au code du pc (carte d'entrées/sorties notament)
    J'utilise aussi le timer.stop() en début de code et je termine par timer.start()
    sachant que je scrute toutes les 100ms en moyenne avec 8 instructions de 10ms chaque cela devient inutile. Sauf que je travail via une dll sur le port USB et le temps de 10ms n'est pas garanti.

    Pour faire simple que ce passe t'il si le code à faire est suppérieur a l'interval ?
    Et pour conclure, quel est alors la différence entre timer.enabled et timer.start ?
    Merci pour votre réponse.

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

    Informations professionnelles :
    Activité : .NET / SQL SERVER

    Informations forums :
    Inscription : Avril 2007
    Messages : 14 177
    Points : 25 119
    Points
    25 119
    Par défaut
    timer.Start fait timer.enabled = true
    (tout comme uneform.show fait uneform.visible = true ^^)

    si le temps de traitement du timer est plus long que l'interval, 2 cas (comme je l'explique avant)
    s'il n'y a pas de timer.stop, le code est executé en continue en gros
    s'il y a un timer.stop, il y a bien une pause défini par l'interval, malgré que le traitement agrandi cet interval

    pour gérer des choses qui arrivent souvent, comme des IO dans ton cas, en général il est préférable de faire un thread séparé, surtout que de nos jours, il y a plusieurs core sur un processeur

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
     
    private sub peu_importe (au démarrage de l'appli par exemple)
      dim th as new system.threading.thread(adressof sub_traitement)
      th.isbackground = true ' permet d'éviter que le processus ne s'arrete pas
      th.start
    end sub
     
    private sub sub_traitement
      while true
        'traitement
        system.threading.thread.sleep(100)
      end while 
    end sub
    ce code équivaut un peu à un timer, une fois le traitement effectué, ca attend 100ms

    avoir plusieurs thread sur un programme équivaut à avoir plusieurs lignes d'execution de code qui avancent en meme temps (visible sur le débugage pas à pas)


    autre exemple, si on a une appli qui dialogue par tcp/ip, on peut avoir une collection qui contient les transferts à effectuer
    le code de l'interface utilisateur ajoute un element à la collection (en général un system.collections.generic.queue(Of ) et un thread s'occupe de transférer

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
     
    private sub thread_envoi
      while true 
        if queue.count = 0 then
          system.threading.thread.sleep(100)
          continue while
        end if
        ' code du transfert, avec un queue.dequeue()
      end while
    end sub
    avec ce code, s'il n'y a rien à envoyer, on ne fait rien et on remonte au début du while
    tant qu'il y a des choses à envoyer, ca envoie sans attendre
    le fait de déporter sur un thread permet de le faire bosser à fond sans bloquer l'interface utilisateur, qui est gérée par le thread principal

    il existe aussi un timer qui n'est pas dans le namespace system.windows.forms, celui ci renvoi son evenement sur un thread séparé, et donc si on ne fait pas de timer.stop la pile des appels peut grandir si le traitement est plus long que l'interval, et l'appli peu planter


    NB : penser à mettre les try catch au bon endroit pour etre sur que le thread ne s'arrete pas, arretant ainsi la fonction qu'il occupait

  5. #5
    Membre régulier
    Homme Profil pro
    Architecte technique
    Inscrit en
    Octobre 2008
    Messages
    83
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52
    Localisation : France, Morbihan (Bretagne)

    Informations professionnelles :
    Activité : Architecte technique
    Secteur : Industrie

    Informations forums :
    Inscription : Octobre 2008
    Messages : 83
    Points : 96
    Points
    96
    Par défaut
    Merci bien pour ce bon tuto.
    En fait j'utilse déja les treads mais pour la gestion du grafcet de process (avec un speudo chien de garde)
    Mais en effet rien de m'empéche d'en creer un second pour l'écriture des IO.
    Note que j'utilise les timer pour les IO car il n'y aucune chance que le timer bloque ou plante l'hmi. Mais je vais suivre ton conseil.
    Note que j'ai eu un peu de mal à enchanger des variables inter tread, et je dois encore utiliser le checkforillégal = false pour éviter les soucis.
    voici le principe que j'utilise peut être que j'oubli un truc ?
    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
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    Dim Grafcet As New System.Threading.Thread(AddressOf Th_Grafcet) ' Declare le thread du grafcet
     
    ' dans le form closing :
            ' tue le thread si actif
            If (Grafcet.IsAlive) Then Grafcet.Abort()
     
    'donc le form load :
            ' Pour annuler une erreur inter/thread
            CheckForIllegalCrossThreadCalls = False
    Grafcet.Start()
     
    'puis enfin le début de son code:
     Sub Th_Grafcet()
            While True  ' a faire tant que mode auto vrai
     
                If Num_Etape > 0 And Num_Etape < 6 And ReadDigitalChannel(1) = False Then
                    LblIdProd.Text = "TEST Annulé Bimanuelle relaché" 'si un prod selectionné
                    LblIdProd.Refresh()
                    Me.BackColor = Color.Orange ' couleur de fond en orange
                    Pause(500)
                    Num_Etape = 0
                End If
     
     
                Application.DoEvents() ' sans bloquer le reste de l'appli
    ' dois servir à rien puisque pas dans le tread principal ???
    ' en revanche rajout d'une pause de 100ms pour redonner la main au tread principal
                Select Case Num_Etape
     
                    '---------------------INIT DU GRAFCET ET ATTENTE SELECTION PRODUIT--------------------
                    Case 0 ' init...... etc....
    Voila si tu vois une bétise, je serais ravi de la connaitre, d'avance merci pour ta critique
    cordialement

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

    Informations professionnelles :
    Activité : .NET / SQL SERVER

    Informations forums :
    Inscription : Avril 2007
    Messages : 14 177
    Points : 25 119
    Points
    25 119
    Par défaut
    .abort c'est moyen
    CheckForIllegalCrossThreadCalls = False c'est vraiment déconseillé
    Application.DoEvents ca serait mieux de l'éviter aussi


    pour le .abort, il vaut mieux essayer de passer par un booléen qui arrete proprement en attendant, et .interrupt serait peut etre meme mieux, le .abort déclenche une erreur, qui peut se produire dans le framework et donc avoir des effets de bords ...


    en multithreading, seuls les controles ne peuvent etre modifiés que par un thread (le thread principal)
    la méthode quand on est sur un thread autre c'est de passer par délégué
    j'ai expliqué les threads et les délégués dans ce post
    http://www.developpez.net/forums/d49...es-difference/
    dans lequel je fais meme un lien vers moi meme avec un exemple plus complet des délégués

    les autres variables (non graphiques donc) peuvent etre manipulées par tout le monde
    par contre ca peut poser des soucis
    sur une collection, si un thread fait .Add pendant qu'un autre fait For Each dessus ca plante
    il y a des moyens de sécuriser du multithreading (synclock, readerwriterlock ...)

  7. #7
    Membre régulier
    Homme Profil pro
    Architecte technique
    Inscrit en
    Octobre 2008
    Messages
    83
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52
    Localisation : France, Morbihan (Bretagne)

    Informations professionnelles :
    Activité : Architecte technique
    Secteur : Industrie

    Informations forums :
    Inscription : Octobre 2008
    Messages : 83
    Points : 96
    Points
    96
    Par défaut
    oouahou, merci bien je postasse tout cela.
    pour le .abort je sais que c'est pas trés propre, mais si j'écris :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    Sub Th_Grafcet()
            While running 'running as boolean
    le tread ne sruct plus le code de GR7, mais il tourne toujours, non ?
    donc faut bien à la fermeture le "tuer", non ?
    ou alors untruc du style TH_grafcet=nothing ? ou dispose ?
    Merci pour les infos.
    cordialement.

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

    Informations professionnelles :
    Activité : .NET / SQL SERVER

    Informations forums :
    Inscription : Avril 2007
    Messages : 14 177
    Points : 25 119
    Points
    25 119
    Par défaut
    pas tout compris

    mais sur un thread qui boucle, il faut un booléen pour sortir du while (à vérifier assez souvent pendant le traitement donc)

    monthread.join() permet d'attendre que le thread s'arrete (utiliser la surcharge avec un timeout sinon ca peut bloquer)
    et donc si le join(timeout) passe en timeout, faire monthread.interrupt, ca arrete l'execution à la ligne en cours ....

    mettre à nothing ne fait rien, et dispose n'est pas possible sur un thread ...

  9. #9
    Membre régulier
    Homme Profil pro
    Architecte technique
    Inscrit en
    Octobre 2008
    Messages
    83
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52
    Localisation : France, Morbihan (Bretagne)

    Informations professionnelles :
    Activité : Architecte technique
    Secteur : Industrie

    Informations forums :
    Inscription : Octobre 2008
    Messages : 83
    Points : 96
    Points
    96
    Par défaut
    En fait la vrai question est plutôt dois-je fermer le thread dans la form closing ?
    J'en ai fait un là juste pour tester tes conseils, et si je fais dans Form1_FormClosing j'ai pas l'impression qu'il tourne toujours.
    i'm write ?
    @ te lire et merci encore

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

    Informations professionnelles :
    Activité : .NET / SQL SERVER

    Informations forums :
    Inscription : Avril 2007
    Messages : 14 177
    Points : 25 119
    Points
    25 119
    Par défaut
    si tu mets isbackground = true avant de faire .Start, le thread s'arretera (comme un .interrupt) au moment ou le thread qui l'a créé s'arretera (donc en gros quand tu fermes l'appli)

    si tu ne mets pas isbackground, la fenetre peut se fermer, mais le thread tourne toujours, et le processus dans windows aussi

    tu peux le fermer toi meme aussi, mais le mieux et d'avoir un booléen à flagger pour tenter un arret propre sinon il faut garder une référence sur le thread et faire .interrupt

    end arrete l'appli, mais de manière plus que déconseillée (tu as le dont pour trouver tout ce qu'il faut pas utiliser ! )

  11. #11
    Membre régulier
    Homme Profil pro
    Architecte technique
    Inscrit en
    Octobre 2008
    Messages
    83
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52
    Localisation : France, Morbihan (Bretagne)

    Informations professionnelles :
    Activité : Architecte technique
    Secteur : Industrie

    Informations forums :
    Inscription : Octobre 2008
    Messages : 83
    Points : 96
    Points
    96
    Par défaut
    vi je sais
    j'ai une culture d'automaticien, alors j'utilise le plus radical à chaque fois
    Maintenant avec .net je suis un peu perdu, ya plein de façon de faire la même chose (sur un automate non !) donc un peu perdu l'@dn...

    quelques exemples qui m'éritent à elle seulent un nouveau post :
    convert.toxxx ou cxxx ?
    cstr ou xxx.tostring ?
    dim xxx() as new integer ou dim xxx as integer = new integer ()
    n'y répond pas je ferais bientôt un post la dessus car les avis divérgent souvent.
    enfin bref comme tu le vois j'ai pas la culture .net (pas faute de lire les tutos, mais bon 15ans d'automatisme formate son monde ^^)

    pour conclure ce super topic sur les timers/thread aurais, stp, tu la gentillesse de poster un code de base pour le fermer proprement (à ta façon je dirais, pour éviter les end, et autres conneries que j'utilise tout le temps )
    d'avance merci de la part d'un qui découvre de plus en plus chaque jour. cordialement @dn.

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

    Informations professionnelles :
    Activité : .NET / SQL SERVER

    Informations forums :
    Inscription : Avril 2007
    Messages : 14 177
    Points : 25 119
    Points
    25 119
    Par défaut
    cstr et ses amis (cbool ...) sont hérités de vb6
    donc les fanatiques te bruleraient sur le bucher s'ils voyaient un cstr

    après il existe reflector, ca permet de décompiler tout ce qui est en .net
    le framework est codé en grande partie en .net, donc on peut voir comment c'est codé derrière
    cstr, ca fait partie du langage vb, pas du framework (ca n'existe pas en c# donc) donc on peut pas voir ce que ca fait, par contre, il suffit de faire une petite appli avec cstr et de regarder avec reflector
    et on voit que c'est transformer en Conversions.ToString(), qui lui meme ne fait que faire .tostring

    bref moi je vais au plus (et en plus je viens de vb6) donc j'écris cstr


    dim xxx() as new integer ou dim xxx as integer = new integer ()
    là c'est pas trop équivalent
    de plus faire un new sur integer ne sert à rien

    donc essaye un peu reflector, c'est un outil qui se lance plusieurs fois par jour quand en développe en .net


    pour les threads :

    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
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
     
        Private _SortieThreadRequise As Boolean
        Private _Thread As System.Threading.Thread
     
        Public Sub DemarreThread()
            _Thread = New System.Threading.Thread(AddressOf Traitement)
            _Thread.Start()
        End Sub
     
     
        Private Sub Traitement()
            While _SortieThreadRequise = False
                Try
                    'traitement dans un try catch pour etre sur de pas sortir sur un bug
                    ' éventuellement un System.Threading.Thread.Sleep(x)
                Catch ex As Exception
                    'enregistrer les erreurs, ca le fait, ca aide à corriger les bugs
                End Try
            End While
        End Sub
     
        Public Sub ArreteThread()
            If _Thread Is Nothing Then Exit Sub
            If _Thread.IsAlive = False Then Exit Sub
            _SortieThreadRequise = True
            _Thread.Join(3000) ' on attend que le thread s'arrete (qu'il passe sur le end sub en gros) ou que 3 secondes se soient écoulées
            If _Thread.IsAlive = False Then Exit Sub ' si le booléen à fait son effet, IsAlive vaut False
            _Thread.Interrupt() ' les gros moyens
        End Sub

  13. #13
    Membre régulier
    Homme Profil pro
    Architecte technique
    Inscrit en
    Octobre 2008
    Messages
    83
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52
    Localisation : France, Morbihan (Bretagne)

    Informations professionnelles :
    Activité : Architecte technique
    Secteur : Industrie

    Informations forums :
    Inscription : Octobre 2008
    Messages : 83
    Points : 96
    Points
    96
    Par défaut
    Merci énormément pour ce pti tuto sur les threads, donc si j'ai bien compris, soit je mets isbackground = true pour qu'il se ferme en même tant que l'appli, soit je gére d'abord son arrêt comme ton code le montre. Le mieux étant d'attendre qu'il se ferme de lui même (cas ou il gére des données ou des streams de fichiers j'imagine)

    Pour ce qui est des convert.toxxx au lieu des cxxx, j'ai lu dans l'aide de VB.NET (j'ai peut être mal compris) que les cxxx hérité du VB6 étaient plus performant que la classe convert.
    En règle générale, vous devez utiliser les fonctions de conversion de Visual Basic de préférence aux méthodes .NET Framework, telles que ToString(), sur la classe Convert, sur une structure de type ou sur une classe. Les fonctions de Visual Basic sont conçues pour une interaction optimale avec le code Visual Basic
    Bon j'y retourne il faut que je trouve comment changer l'image d'un control de la form principal via le thread ^^ (oui je sais tu me l'as dis, un thread ne peut pas toucher à un control graphique, donc je passe par une sub qui est appellé par ce thread) Maintenant le soucis c'est que je créé ces controls par code, et du coup pour y faire appel aprés, ben spa simple puisqu'il n'existe pas encore Comme tu le vois j'aime bien la torture
    @ bientôt et encore merci pour le code.

Discussions similaires

  1. [Débutant] Question simple sur les checkbox
    Par Mil17 dans le forum Servlets/JSP
    Réponses: 2
    Dernier message: 01/08/2007, 15h05
  2. [MySQL] Question simple sur les tableaux pour un initié
    Par bom8407@hotmail.com dans le forum PHP & Base de données
    Réponses: 7
    Dernier message: 01/03/2007, 11h22
  3. Réponses: 4
    Dernier message: 16/11/2006, 02h10
  4. question simple sur les select dynamiques
    Par grinder59 dans le forum Général JavaScript
    Réponses: 7
    Dernier message: 24/01/2006, 15h53
  5. Question simple sur les threads :)
    Par momox dans le forum C++Builder
    Réponses: 2
    Dernier message: 15/06/2003, 04h13

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