Problème DoEvents

Résolu
Nicolas H. Messages postés 36 Date d'inscription vendredi 19 octobre 2001 Statut Membre Dernière intervention 26 mai 2016 - 25 juil. 2011 à 23:30
 Utilisateur anonyme - 3 août 2011 à 01:05
Bonjour,

Je développe un petit GUI pour le backup de mes DVD (méthode perso).

Dans cette appz je lance plusieurs process x264 et je récupère les infos via le code de riadhh05 (http://www.vbfrance.com/codes/REDIRECTION-APPLICATION-CONSOLE-VERS-TEXTBOX_44925.aspx).

Mon problème est qu'en plus des process x264, je lance d'autre fonction comme l'enco du son, la génération de D2V ou la génération d'IDX, via une autre exécution de process avec encore une foi des DoEvents.

Si un job x264 se termine et lance le suivant pendant un rip son le DoEvents semble être redirigé vars le process x264 et bloque l'enco son suivant jusqu'à la fin du process x264.

Je viens de trouver qq info sur les threads qui semble pas mal.

Ceci devrait je pense résoudre mon problème mais après test du code ([VB.NET 2008] EXECUTION MULTITHREAD DE PLUSIEURS FONCTION À L'AIDE D'UN MANAGER DE THREAD) de ShadowTzu.

Le système bouffe pas mal ressource ~32% du CPU alors que mon DoEvents (defect) lui ne demande que 10 à 13% du CPU.

Qqu aurait-il une idée des ressources et de la fiabilité des threads ou comment je peux gérer ma redirection de DoEvents.


Désolé pour la tartine,
Nico

27 réponses

Utilisateur anonyme
31 juil. 2011 à 14:39
Bonsoir,

La solution de NHenry du 28 juillet fonctionne parfaitement.
Je me suis permis de la mettre en oeuvre pour la tester.
J'ai formé une classe clsThread pour chaque thread lancé pour la simplicité de manipulation (noms, arguments, état de la tâche effectuée)
Option Strict On
Imports System.Threading

Public Class clsThread
    'initialisation d'un nouveau thread
    Dim t As New Thread(AddressOf Job)
    'variable de stockage de l'état de la tâche
    Dim m_tacheOK As Boolean
    'initilaisation d'un générateur de nombre aléatoire pour l'exemple
    Dim rd As New Random(System.DateTime.Now.Millisecond)

    'on renseigne ici le nom du thread ainsi que les arguments à passer au thread
    'les arguments peuvent contenir un nom d'exécutable à lancer des paramètres etc
    'ils peuvent être de type Objet (classe, tableau, collection etc...)
    Sub New(ByVal Name As String, ByVal Arguments As String)
        t.Name = Name
        t.Start(Arguments)
    End Sub

    Private Sub Job(ByVal args As Object)
        'on caste les arguments qui sont de type Objet par defaut
        Dim Arguments As String = DirectCast(args, String)
        'tache ici à faire 
        'process.start() ....
        'do while process.hasexited = false ....
        'j'ai remplacé par un sleep de durée aléatoire pour l'exemple
        Thread.Sleep(rd.Next(1000, 20000))
        'la tâche est éffectuée : on affecte true à la variable
        m_tacheOK = True
    End Sub

    ReadOnly Property TacheOK() As Boolean
        Get
            Return m_tacheOK
        End Get
    End Property

    ReadOnly Property Name() As String
        Get
            Return t.Name
        End Get
    End Property

    ReadOnly Property Thread() As Thread
        Get
            Return t
        End Get
    End Property
End Class


Et le code du formulaire pour le contrôle par timer.
J'ai rajouté un bouton pour le lancement d'un thread manuellement.
Option Strict On
Public Class Form1
    'liste principale des threads
    Dim ListeT As New List(Of clsThread)
    'timer de contrôle de la liste des threads
    Dim WithEvents tmr As New Timer
    'bouton de lancement manuel d'un thread
    Dim WithEvents buttonT As New Button
    'variable de comptage des threads pour l'exemple
    Dim m_nb As Integer

    Private Sub Form1_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
        buttonT.Text = "Lancement"
        Me.Controls.Add(buttonT)
        'lancement de 3 threads (ajout dans la liste principale)
        For x = 0 To 2
            m_nb += 1
            ListeT.Add(New clsThread("thread " & m_nb.ToString, "-p X"))
        Next
        'lancement du timer de contrôle
        tmr.Interval = 500
        tmr.Start()
    End Sub

    Private Sub tmr_Tick(ByVal sender As Object, ByVal e As System.EventArgs) Handles tmr.Tick
        'on initialise une nouvelle liste provisoire de threads
        'en effet, on ne peut pas modifier une liste(ajout/suppression) au cours d'une boucle for each
        Dim listets As New List(Of clsThread)
        'pour chaque threads dans la liste des threads
        For Each th As clsThread In ListeT
            'si la tâche est terminée
            If th.TacheOK Then
                m_nb += 1
                Debug.Print(th.Name & " à fini sa tâche. Lancement du thread " & m_nb.ToString)
                th.Thread.Abort()
                th = Nothing
                'on rajoute un (ou plusieurs) thread qui lance une nouvelle tâche
                'remarque : le thread qui à fini (th) et qui est détruit  n'est plus ajouté dans la liste.
                listets.Add(New clsThread("thread " & m_nb.ToString, "-p X"))
            Else
                'sinon on ajoute le thread en fonctionnement dans la liste provisoire
                listets.Add(th)
            End If
        Next
        'on actualise la liste principale des threads
        ListeT = listets
    End Sub

    Private Sub buttonT_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles buttonT.Click
        'on ajoute un thread manuellement en cliquant sur le bouton
        m_nb += 1
        ListeT.Add(New clsThread("thread " & m_nb.ToString, "-p M"))
        Debug.Print("Lancement manuel du thread " & m_nb.ToString)
    End Sub
End Class


En espérant que ceci puisse te servir.
Bonne soirée.
3
NHenry Messages postés 15069 Date d'inscription vendredi 14 mars 2003 Statut Modérateur Dernière intervention 29 mai 2023 158
26 juil. 2011 à 21:52
Bonjour,

Il faut voir comment tu as codé ton thread, car si tu ne lui a pas mis un Sleep au milieu, c'est normal, mais il faut en voir plus.
(Penses à la coloration syntaxique, 3ième icône en partant de la droite)

Mon site
0
Nicolas H. Messages postés 36 Date d'inscription vendredi 19 octobre 2001 Statut Membre Dernière intervention 26 mai 2016 1
26 juil. 2011 à 22:22
Bonjour,

Pour le moment il n'y en a pas.

Je suis occupé à essayer d'utiliser les threads :)

Donc en gros j'ai une form1 qui lance mes jobs comme ceci et en load un autre quand il et fini :

Friend mDVD_JOB1 As WinConsole
...
mDVD_JOB1 = New WinConsole(ApplicationName, ApplicationParameters, Me.debug1)
mDVD_JOB1.InitializeMyProcess(Me)
mDVD_JOB1.InitializeMyProcessStartInfo()
Try
mDVD_JOB1.myProcess.StartInfo = mDVD_JOB1.myProcessStartInfo
mDVD_JOB1.myProcess.Start()
mDVD_JOB1.myProcess.BeginErrorReadLine()
mDVD_JOB1.myProcess.BeginOutputReadLine()
Catch ex As Exception
mDVD_JOB1.WriteText(ex.Message)
End Try
...
Do
Application.DoEvents()
Loop Until mDVD_JOB1.HasExited
mDVD_JOB1.myProcess.WaitForExit()


Et une autre form2 qui les lance comme ceci :

Private pD2V As Process

Public Function D2V(ByVal NAME As String, ByVal EPS As String) As Boolean
pD2V = New Process()
pD2V.StartInfo.FileName = %Path_EXE%
If My.Computer.FileSystem.FileExists(%FileIn%) Then
pD2V.StartInfo.Arguments = "..."
pD2V.Start()
Do
Application.DoEvents()
Loop Until pD2V.HasExited
pD2V.WaitForExit()
End If
Return My.Computer.FileSystem.FileExists(%FileOut%)
End Function


Tous fonctionne bien sauf que quand la form1 load un autre job, le job de la form2 se termine et le suivant attend la fin du job de la form1.
0
Nicolas H. Messages postés 36 Date d'inscription vendredi 19 octobre 2001 Statut Membre Dernière intervention 26 mai 2016 1
28 juil. 2011 à 21:39
Je ne trouve rien avec les threads ou autre qui ne freez pas le soft, qui ne me lance pas tous les jobs d'un coup ou qui ne me fasse pas la même chose.

Si quelqu'un a une idée, je prends.

Je vais encore passer mon week-end la dessus et si je ne trouve rien qui fonctionne.

Je garde mon batch qui fait la même chose mais tourne super bien ;)
0

Vous n’avez pas trouvé la réponse que vous recherchez ?

Posez votre question
NHenry Messages postés 15069 Date d'inscription vendredi 14 mars 2003 Statut Modérateur Dernière intervention 29 mai 2023 158
28 juil. 2011 à 21:47
Bonjour,

Il aurait été préférable que tu utilises la coloration syntaxique, cela rend le code plus facile à lire.

Sinon, pour les threads, renseignes-toi dessus, car ça peut être utile.

Pour la boucle d'attente :
Do
    Application.DoEvents()
Loop Until mDVD_JOB1.HasExited


Mets un System.Threadding.Thread.Sleep à l'interieur, ça limitera la conso CPU.

Tu peux aussi utiliser un Timer pour monitorer le processus (ou un thread).

--------------------------------------------------
[list][*]Quand vous postez un code, merci d'utiliser la coloration syntaxique (3ième icône en partant de la droite : )
[*]Si votre problème est résolu, pensez à mettre "Réponse acceptée" sur le ou les messages qui vous ont aidés./list---
Mon site
0
Nicolas H. Messages postés 36 Date d'inscription vendredi 19 octobre 2001 Statut Membre Dernière intervention 26 mai 2016 1
28 juil. 2011 à 22:24
Sorry, je viens de comprendre pour la coloration syntaxique.

Savoir si le process est exécuté ou pas n'est pas un problème.

Je cherche à ne pas avoir de coupure dans les boucles.

Si je lance 4 enco vidéo et 20 enco son. Actuellement le 13ème enco son attend la fin de l'enco vidéo qui s'est exécuté pendant l'enco son 12.

J'ai des contrôles d'exécution mais je ne veux pas de pause dans mes boucles car un autre job se lance.

Avec le timer pour ce que j'ai trouvé et testé, il faut prévoir une fermeture forcée et empêcher le freez de l'appz.

Et je n'ai encore rien trouvé pour relancer la boucle en pause sans killer le job qui a mis la boucle en pause.

Tu aurais un exemple de ta soluce car il est possible que je ne voix pas la même chose que toi.
0
NHenry Messages postés 15069 Date d'inscription vendredi 14 mars 2003 Statut Modérateur Dernière intervention 29 mai 2023 158
28 juil. 2011 à 22:33
Bonjour,

Il te faut enregistrer une liste de processus dans une collection : List(Of ... )

Ensuite, pour chaque tache, tu l'ajoute dans la liste une fois lancée et un Timer contrôlera quels processus se sont arrêtés et agira en conséquence.

--------------------------------------------------
[list][*]Quand vous postez un code, merci d'utiliser la coloration syntaxique (3ième icône en partant de la droite : )
[*]Si votre problème est résolu, pensez à mettre "Réponse acceptée" sur le ou les messages qui vous ont aidés./list
---
Mon site
0
Nicolas H. Messages postés 36 Date d'inscription vendredi 19 octobre 2001 Statut Membre Dernière intervention 26 mai 2016 1
30 juil. 2011 à 14:05
Bonjour,

NHenry: merci pour tes conseilles

Je viens de passer ma nuit la dessus. Les threads, le cross thread, le timer, etc...

J'ai tout testé sans résultat, je vais arrêter les frais ici.

Ayant arrêté le VB il y a 8 ou 9 ans, je ne vais finalement pas pouvoir faire la transition au .Net en 3 semaines :)

Le soft fonctionne avec un bug, je vais commenter le code faire un peu de nettoyage et le poster.

Il pourra peut-être servir à quelqu'un.
0
NHenry Messages postés 15069 Date d'inscription vendredi 14 mars 2003 Statut Modérateur Dernière intervention 29 mai 2023 158
30 juil. 2011 à 14:12
Bonjour,

D'accord, c'est vrai que les langages de programmations ne sont pas toujours évidents à utiliser.

Bon codage :)

---------------------------------------------------------------------
[list][*]Quand vous postez un code, merci d'utiliser la coloration syntaxique (3ième icône en partant de la droite : )
[*]Si votre problème est résolu, pensez à mettre "Réponse acceptée" sur le ou les messages qui vous ont aidés./list
---
Mon site
0
Nicolas H. Messages postés 36 Date d'inscription vendredi 19 octobre 2001 Statut Membre Dernière intervention 26 mai 2016 1
1 août 2011 à 20:51
Bonsoir,

banana32 : Merci pour la démo, je vais bien regarder, tester et voir pour comprendre et l'intégrer dans mon soft.

Je n'ai pas su mettre en place la solution de NHenry faute de maîtrise du language et d'exemple.

A mon stade une démo vaut mieux que mille mots. J'ai besoin d'un ou deux exemples pour comprendre, le langage et m'adapter.

NHenry : Sorry, si j'ai sous entendu que ta solution ne fonctionnait pas.


J'ai arrêté samedi, j'ai rien foutu dimanche et je me suis remis à y pensé aujourd'hui.

J'aime les cases tête.


Je venais de trouver un soluce avec le timer, la voici :

    Sub IDX(ByVal NAME As String, ByVal EPS As String, ByVal SelItem As Integer)
        Dim FldAudio As Integer = EPS.Split("/")(0)
        pIDX = New Process()
        EPS = FormatEPS(EPS)  'je le format 01 ou 001 pour les tests de fin d'exécution
        pIDX.StartInfo.FileName = Settings.VobSub.Text
        SubStp = False  'j'enpêche l'arret
        pIDX.Start()
        SubId = pIDX.Id  'stockage interger pour utilisation dans le timer
        If Process.GetProcessById(SubId).Responding Then TimeJob.Enabled = True  'je test la bonne exécution du process et je lance le timer
        Do
            Thread.Sleep(50)
            Application.DoEvents()
        Loop Until SubStp
        SubId = -1
        ...
    End Sub


    Private Sub TimeJob_Tick(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles TimeJob.Tick
        Dim Found As Boolean = False
        If SubId > -1 Then
            'je liste les process et je check si le mien y est
            For Each p As Process In Process.GetProcesses
                If p.Id SubId Then Found True
            Next
            'si il n'y est pas c'est qu'il est fini
            If Not Found Then
                SubStp = True 'je stop ma boucle
                TimeJob.Enabled = False 'je stop le timer
            End If
        End If
    End Sub



banana32 : Comme je viens de voir ton code, je reg now.
0
NHenry Messages postés 15069 Date d'inscription vendredi 14 mars 2003 Statut Modérateur Dernière intervention 29 mai 2023 158
1 août 2011 à 21:03
Bonjour,

Nicolas H., pas grave, mais la programmation n'est pas toujours évidente.
Si ton pb est résolu, penses à mettre "Réponse acceptée" sur le ou les messages qui t'ont aidés.
Sinon, précise le(s) point(s) qui bloque(nt)

---------------------------------------------------------------------
[list][*]Quand vous postez un code, merci d'utiliser la coloration syntaxique (3ième icône en partant de la droite : )
[*]Si votre problème est résolu, pensez à mettre "Réponse acceptée" sur le ou les messages qui vous ont aidés./list
---
Mon site
0
Nicolas H. Messages postés 36 Date d'inscription vendredi 19 octobre 2001 Statut Membre Dernière intervention 26 mai 2016 1
2 août 2011 à 00:46
banana32 :

J'ai un petit problème d'adaptation et je ne trouve pas la solution.

Le timer détect bien TacheOK à True mais ne lance pas la suite.

Peux tu m'aider ?



Public Class MyForm

    Private Sub bAUDIO_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles bAUDIO.Click
        ...
        For i As Integer = 0 To JobQueue.SelectedItems.Count - 1
            ...
            Select Case JobQueue.Items(i).SubItems(1).Text
                Case "DVD"
                    Dim nItem As New ListViewItem(i)
                    nItem.SubItems.Add(FileName & "#" & Arguments)
                    MyJobList.Items.Add(nItem)   'OK
                Case "BD"
                    '
            End Select
        Next
        If MyJobList.Items.Count > 0 Then
            ListeT.Add(New clsThread(MyJobList.Items(0).SubItems(0).Text, MyJobList.Items(0).SubItems(1).Text))   'OK
            MyJobList.Items(0).Remove()   'OK
            TimeJob.Interval = 500   'OK
            TimeJob.Start()   'OK
        End If
    End Sub

 
   Private Sub TimeJob_Tick(ByVal sender As Object, ByVal e As System.EventArgs) Handles TimeJob.Tick
        Dim listets As New List(Of clsThread)
        For Each th As clsThread In ListeT
            If th.TacheOK Then   'OK (Détect True à interval)
                MsgBox("job ok")   ' ne s'affiche pas
                th.Thread.Abort()
                th = Nothing
                ...
                If MyJobList.Items.Count > 0 Then
                    listets.Add(New clsThread(MyJobList.Items(0).SubItems(0).Text, MyJobList.Items(0).SubItems(1).Text))
                    MyJobList.Items(0).Remove()
                Else
                    TimeJob.Stop()
                    ...
                End If
            End If
        Next
        ListeT = listets
    End Sub

End Class


Public Class clsThread
    ...
    Private mProcess As Process

    Private Sub Job(ByVal args As Object)
        Dim Arguments As String = DirectCast(args, String)
        mProcess = New Process()
        mProcess.StartInfo.FileName = Arguments.Split(CChar("#"))(0)
        mProcess.StartInfo.Arguments = Arguments.Split(CChar("#"))(1)
        mProcess.Start()   'OK
        Do While mProcess.HasExited = False   'OK
            'Thread.Sleep(50)
            Application.DoEvents()
        Loop
        mProcess.WaitForExit()
        m_tacheOK = True   'OK
    End Sub
    ...
End Class

0
NHenry Messages postés 15069 Date d'inscription vendredi 14 mars 2003 Statut Modérateur Dernière intervention 29 mai 2023 158
2 août 2011 à 10:34
Bonjour,

Un problème de cache est possible si tu utilises des threads, pour éviter ce problème, il faut lire et écrire les variables échangées en Volatile.

VB.NET ne propose pas cela de manière native, mais voici une alternative :
Function VolatileRead(Of T)(ByRef Address As T) As T
    VolatileRead = Address
    Threading.Thread.MemoryBarrier()
End Function

Sub VolatileWrite(Of T)(ByRef Address As T, ByVal Value As T)
    Threading.Thread.MemoryBarrier()
    Address = Value
End Sub


Pour lire :
If VolatileRead(MaVariable) Then
Pour écrire :
VolatileWrite(MaVariable,"MaValeur")

---------------------------------------------------------------------
[list][*]Quand vous postez un code, merci d'utiliser la coloration syntaxique (3ième icône en partant de la droite : )
[*]Si votre problème est résolu, pensez à mettre "Réponse acceptée" sur le ou les messages qui vous ont aidés./list
---
Mon site
0
Nicolas H. Messages postés 36 Date d'inscription vendredi 19 octobre 2001 Statut Membre Dernière intervention 26 mai 2016 1
2 août 2011 à 20:59
Bonsoir,

Je viens de tester tes fonction NHenry mais il n'y a pas de changement.

J'ai encore fait des recherches mais je ne trouve rien, je vais à l'erreur et rien.

    Private Sub TimeJob_Tick(ByVal sender As Object, ByVal e As System.EventArgs) Handles TimeJob.Tick
        Dim listets As New List(Of clsThread)
        For Each th As clsThread In ListeT
            If VolatileRead(th.TacheOK) Then
                th.Thread.Abort()
                th = Nothing
                listets.Add(New clsThread(MyJobList.Items(0).SubItems(0).Text, MyJobList.Items(0).SubItems(1).Text))
                MyJobList.Items(0).Remove()
            End If
        Next
        ListeT = listets
    End Sub


Je ne comprend vraiment pas ce qui se passe ou ce qui ne se passe pas.
0
NHenry Messages postés 15069 Date d'inscription vendredi 14 mars 2003 Statut Modérateur Dernière intervention 29 mai 2023 158
2 août 2011 à 21:09
Bonjour,

As-tu regardé en pas à pas les valeurs des variables

---------------------------------------------------------------------
[list][*]Quand vous postez un code, merci d'utiliser la coloration syntaxique (3ième icône en partant de la droite : )
[*]Si votre problème est résolu, pensez à mettre "Réponse acceptée" sur le ou les messages qui vous ont aidés./list
---
Mon site
0
Utilisateur anonyme
2 août 2011 à 21:12
Bonsoir,

Enlève MsgBox.
Met un point d'arrêt sur If th.TacheOk Then et exécute en pas à pas (F8).
Y a t-il une exception levée ?
Pourquoi avoir mis WaitForExit ?
Profites-en pour lire les Notes de msdn :
Cette méthode indique au composant Process d'attendre les gestionnaires d'événements et processus une durée infinie pour s'arrêter. Une application peut alors cesser de répondre.

Si MyJobList est un composant (control) placé sur un thread différent tu vas devoir utiliser les délégués.
Remplace MsgBox par MessageBox.show()
Tiens nous au courant.

Bonne soirée.
0
Utilisateur anonyme
2 août 2011 à 21:20
Ah et vire moi cet immonde Application.DoEvents lol
0
Nicolas H. Messages postés 36 Date d'inscription vendredi 19 octobre 2001 Statut Membre Dernière intervention 26 mai 2016 1
2 août 2011 à 22:19
NHenry :

Q: As-tu regardé en pas à pas les valeurs des variables ?
R: En pas à pas non, je suis occupé dessus mais j'ai testé avec un msgbox juste avant le If. Il m'affiche bien th.TacheOK à true (à l'interval du timer) une foi le process terminé.


banana32 :

MyJobList =
Dim MyJobList As New ListView
(dans la même Form que le timer.)

Q: Pourquoi avoir mis WaitForExit ?
R: Pour attendre la fin du process, si il n'est pas fermé le thread ne se fermera pas. J'ai testé avec un
If mProcess.Responding Then ...
Pour générer une erreur (J'ai bien une erreur).

Pour se que j'ai vu le WaitForExit(x) est une attente avant un Close() puis un Kill() au cas ou.


Demande: Ah et vire moi cet immonde Application.DoEvents
Pas moyen l'appz ne repond plus, si je le supprime. De même pour le sleep si je le garde je dois détecter le stop du process via un timer sinon il rate souvent la fin du process. Ce qui bloque les jobs suivant.



Bon j'ai mis le point d'arrêt F8 ...

Je lance mon job ... (je bloque l'enco pour que le soft reste ouvert et je reg la boucle)

Il passe une ou deux fois sur le
If th.TacheOK Then
après il zap la boucle.

ListeT | Count = 0

Et avec :

    Private Sub TimeJob_Tick(ByVal sender As Object, ByVal e As System.EventArgs) Handles TimeJob.Tick
        Dim listets As New List(Of clsThread)
        For Each th As clsThread In ListeT
            MsgBox(th.TacheOK)
            If th.TacheOK Then
                ...
            End If
        Next
        ListeT = listets
    End Sub



J'ai bien un message false et une foi le soft fermé j'ai true à interval.
0
Nicolas H. Messages postés 36 Date d'inscription vendredi 19 octobre 2001 Statut Membre Dernière intervention 26 mai 2016 1
2 août 2011 à 22:25
C'est pareil avec
VolatileRead(th.TacheOK)
0
Utilisateur anonyme
2 août 2011 à 22:32
Pas moyen l'appz ne repond plus, si je le supprime.

Do While mProcess.HasExited = False   'OK
    'Thread.Sleep(50)
    Application.DoEvents()
Loop

Je te rappelle que tu est dans un thread. Ca m'étonnerais beaucoup que cela bloque le thread principal.
Tu peux décommenter Thread.Sleep(50) par contre.
Je te conseille de coller le code complet, quelque chose ne se passe pas bien ailleurs.
0