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

  1. #1
    Membre à l'essai
    Homme Profil pro
    Développeur Web
    Inscrit en
    mars 2017
    Messages
    25
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 31
    Localisation : France, Gard (Languedoc Roussillon)

    Informations professionnelles :
    Activité : Développeur Web
    Secteur : High Tech - Multimédia et Internet

    Informations forums :
    Inscription : mars 2017
    Messages : 25
    Points : 18
    Points
    18

    Par défaut Application WinForm qui reste en processus en arrière plan après fermeture

    Salut à tous.

    Me revoilà avec mon application Winform

    Aujourd'hui j'ai constaté que quand l'application se ferme, elle se met en processus d'arrière plan.

    Voici le cheminement de connexion à la BDD lors de l'ouverture et la fermeture de l'application :

    Connexion BDD
    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
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
     
    /// <summary>
            /// Arrête la connexion à la fermeture du dashbord
            /// </summary>
            public static void KillConnexion()
            {
                zCnx.Close();
                zCnx.Dispose();
                zCnx = null;
            }
     
    public static Boolean bOpenConnection()
            {
                try
                {
                    if(zCnx == null)
                    {
                        // Test : Mode débug actif ?
                        //bool bDebug = System.Diagnostics.Debugger.IsAttached;
     
                        bool bDebug = false;
     
    #if DEBUG
                        bDebug = true;
    #endif
     
                        // Test : En mode débug ?
                        if (bDebug)
                        {
                            zCnx = new MySqlConnection("Persist Security Info=False;Server="";Database="";Uid="";Pwd=""");
                            zCnx.Open();
                        }
                        else
                        {
                            // Mise à jour du serveur
                            MajServeurs();
                            // prod
                            zCnx = new MySqlConnection("Persist Security Info=False;Server=" + zsServeurMySql + ";Database="";Uid="";Pwd=""");
                            zCnx.Open();
                        }
     
     
                    } // Test : En mode débug ?
     
     
                    return true;
                }
                catch (Exception e)
                {
                    cl_Logger.writeError(WindowsIdentity.GetCurrent().Name, "cl_DbConnection", "openConnection", e);
                    // Erreur
                    return false;
                }
            }
    Chargement
    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
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
     
    public partial class frm_Chargement : Form
        {
            public frm_Chargement()
            {
                InitializeComponent();
                this.Text = "Chargement de l'application - " + cl_Configuration.numeroVersion;
            }
     
            /// <summary>
            /// Lorsque la fenêtre s'affiche.
            /// </summary>
            /// <param name="sender"></param>
            /// <param name="e"></param>
            private void frm_Chargement_Shown(object sender, EventArgs e)
            {
                //La fenêtre de chargement ne charge que les données nécessaire à l'ouverture de l'application,
                //le reste des données est chargé de façon asynchrone
                Thread t = new Thread(Initialisation);
                t.Start();
                while (t.IsAlive)
                {
                    Application.DoEvents();
                }
                this.Close();
            }
     
            /// <summary>
            /// Méthode permettant de récupérer les informations nécessaire à l'ouverture de l'application
            /// </summary>
            public void Initialisation()
            {
     
                //Récupérer l'indentifiant session
                String strNameWindows = WindowsIdentity.GetCurrent().Name;
     
                //Récupérer le nombre de caractère qu'il y a jusqu'au nom de l'utilisateur
                int nCaractere = strNameWindows.IndexOf(@"\");
     
                // Test : Ouverture de la connexion à la base de données
                if (!cl_DbConnection.bOpenConnection()) 
                {
                    MessageBox.Show("Connexion au serveur impossible");
                    // Fermeture de l'application
                    Environment.Exit(0);
                } // Test : Ouverture de la connexion à la base de données
     
                //Déclaration des objets
                cl_CollaborateurBUS userbus = new cl_CollaborateurBUS();
                cl_PrevisionBUS PreviBUS = new cl_PrevisionBUS();
     
                //Variable qui va contenir le login
                string strName = null;
     
                //exemple : kevinpl
                strName = strNameWindows.Substring(nCaractere + 1, strNameWindows.Length - nCaractere - 1);
                //strName = "alaeddine";
                // Test : Mode débug actif ?
                if (System.Diagnostics.Debugger.IsAttached)
                {
                    //strName = "pierrot";
                    //strName = "Aurelienb";
                    //strName = "fabienne";
                    //strName = "alaeddine";
                } // Test : Mode débug actif ?
     
                // si le nom de domaine est ISILAND
                if (strNameWindows.Substring(0, nCaractere) == "ISILAND" )
                {
                    //si il n'y a pas d'utilisateur dont le login commence par le nom passé en parametre 
                    if (userbus.checkDoublon(strName))
                    {
                        //Récupérer l'objet utilisateur
                        cl_Collaborateur.CurrentUser = userbus.getUserByLogin(strName);
                    }
                }
                else
                {
                    MessageBox.Show("Le nom de domaine est incorrecte");
                    // Fermeture de l'application
                    Environment.Exit(0);
                }
            }
     
            /// <summary>
            /// Récupère les informations supplémentaires (par ex. les droits de l'utilisateur) à partir des webservices
            /// </summary>
            public void Rafraichir()
            {
                cl_CollaborateurBUS UserBUS = new cl_CollaborateurBUS();
                cl_PrevisionBUS PreviBUS = new cl_PrevisionBUS();
     
                List<cl_Collaborateur> liste = new List<cl_Collaborateur>();
     
                //Vérifie si l'utilisateur est RPA ou non
                cl_Collaborateur.RPA = UserBUS.checkRPA(UserBUS.getUserCodeCollab(cl_Collaborateur.CurrentUser.idcollaborateur).CodeCollab);
     
                //Récupère la liste des collaborateurs que l'utilisateur courant peut affecter
                string[] strListe = UserBUS.getListeCollaborateurAutorise(UserBUS.getUserCodeCollab(cl_Collaborateur.CurrentUser.idcollaborateur).CodeCollab);
     
                //Insère dans une liste static des objets utilisateur pouvant être affecter par l'utilisateur courant
                foreach (string strCodeCollab in strListe)
                {
                    liste.Add(UserBUS.getUserAutorise(strCodeCollab));
                }
     
                //liste des utilisateurs dont l'utilisateur courant à la responsabilité
                cl_Collaborateur.LstUsers = liste;
     
                //Actualiser la liste des jours non-travaillés de la période allant de trois mois auparavavant jusqu' a trois mois après la date actuelle
                PreviBUS.setListJourNonTravaille();
     
                //Actualiser la liste des prévisions de temps partiel de la période allant de trois mois auparavant jusqu'a trois mois apres la date actuelle.
                PreviBUS.setLstPrevisionTpsPartiel();
     
            }
    Lors de la fermeture de l'application
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
     
    protected override void Dispose(bool disposing)
            {
                if (disposing && (components != null))
                {
                    components.Dispose();
                }
                base.Dispose(disposing);
                cl_DbConnection.KillConnexion();
            }
    Et la classe program
    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
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
     
    static class Program
        {
            /// <summary>
            /// Point d'entrée principal de l'application.
            /// </summary>
            [STAThread]
     
            static void Main()
            {
                // French (fr)
                System.Threading.Thread.CurrentThread.CurrentCulture = new System.Globalization.CultureInfo("fr-FR");
                System.Threading.Thread.CurrentThread.CurrentUICulture = new System.Globalization.CultureInfo("fr-FR");
     
                Application.EnableVisualStyles();
                Application.SetCompatibleTextRenderingDefault(false);
     
                frm_Chargement frmCharg = new frm_Chargement();
                //L'affichage de la fenêtre de chargement entraîne le chargement des données
                frmCharg.Show();
     
                // Chargement des droits du collaborateur
                Application.DoEvents();
                frmCharg.Rafraichir();
     
                //Si l'utilisateur est RPA, ouverture d'une fenêtre responsable
                if (cl_Collaborateur.RPA)
                {
                    frm_Responsable frmResponsable = new frm_Responsable();
                    frmResponsable.Show();
                    //Application.Run(new frm_Responsable());
                }
                //Sinon, actualisation du plan de charge de la fenêtre collaborateur
                else
                {
                    frm_Collaborateur frmCollab = new frm_Collaborateur();
                    //Affichage d'une fenêtre collaborateur
                    frmCollab.Show();
                }
     
                //Permet à l'application de continuer de tourner à la fin des traitements
                Application.Run();
     
            }
        }
    Je n'ai absolument aucune idée de pourquoi ça peut faire ça !
    Merci d'avance

  2. #2
    Expert confirmé
    Avatar de StringBuilder
    Homme Profil pro
    Chef de projets
    Inscrit en
    février 2010
    Messages
    3 565
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 40
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Chef de projets
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : février 2010
    Messages : 3 565
    Points : 5 964
    Points
    5 964
    Billets dans le blog
    1

    Par défaut

    Un programme qui reste chargé en sortie est généralement un programme qui ne libère pas convenablement ses ressources.

    Ceci est souvent dû à des instances d'objets IDisposable (faisant appel à des ressources non managées) qui n'ont pas été correctement disposé.


    Ouvrir une connexion persistante de bout en bout de l'exécution du programme est une très mauvaise pratique.
    En effet, la connexion est un objet IDisposable, non managé.
    Cela veut dire que si ton programme sort d'une manière non prévue, alors la connexion ne sera pas libérée.

    Mais cela veut dire aussi que si tu as une coupure réseau, même une micro-coupure, alors la connexion tombe dans un état second et ton programme va à coup sûr mal le gérer et planter... accessoirement en laissant la ressource ouverte.

    Cela veut dire aussi que si tu écrits une transaction et que tu oublies de la terminer, elle va rester ouverte jusqu'à la fermeture du programme. Les conséquence peuvent être désastreuses : faire un rollback en fin de semaine d'une transaction initiée le lundi matin, c'est vraiment pas cool... et locker des ressources de plus en plus nombreuses a fil de la journée, c'est pas cool non plus pour les autres !

    Bref : la connexion, on l'ouvre le plus part possible, et on la ferme le plus tôt possible.

    Ouvrir et fermer une connexion pour chaque requête est une meilleure pratique que d'ouvrir une connexion le lundi matin et la fermer le vendredi soir.

    Dans l'idéal, on ouvre la connexion au début de chaque traitement, et on la ferme à la fin de chaque traitement.

    Pourquoi ?
    - Lorsqu'une personne utilise l'application, les temps de traitements dans la base de données sont de l'ordre de moins de 1% du temps de saisie. Ceci implique que laisser une connexion ouverte consomme des ressources (et une licence si on est en mode connexions concurrentes) 99% du temps pour rien.
    - Tous les SGBD dignes de ce nom, y compris MySQL, c'est pour dire, possèdent un "pool de connexion". C'est à dire qu'en réalité le SGBD ne va pas réellement ouvrir et fermer une connexion à chaque accès : il va simplement réutiliser une connexion déjà ouverte, libre, puis la libérer : ceci permet d'avoir 1000 personnes connectées en simultané qui ne consomment que 10 connexions parallèles.
    - Si tu travailles avec un objet connexion instancié dans un bloc "using", alors quelle que soit la manière dont tu sors du bloc, la connexion sera forcément fermée et libérée.
    - Si la connexion ne reste jamais ouverte plus de 2 secondes d'affilées au lieu de 5 jours, les risque de micro-coupure est quelque peu diminué, améliorant sensiblement la stabilité de l'application.

    Sinon, pour essayer de résoudre ton problème sans tout réécrire, tu peux tenter de rajouter dans tous les Form_Closed de ton application un GC.Collect().
    Mais sans fermer proprement la connexion avant, il y a peu de chances que ça change grand chose (même si au pire ça peut pas faire de mal).

    Ah, et j'oubliais... afin d'éviter de s'emmêler les pinceaux avec MARS, des transactions croisées et autres blocages, il ne faut jamais utiliser la même connexion dans deux threads différents : chaque thread doit disposer de sa propre connexion (ce qui est automatiquement le cas si tu ouvres et fermes ta connexion à chaque traitement).
    On ne jouit bien que de ce qu’on partage.

  3. #3
    Membre à l'essai
    Homme Profil pro
    Développeur Web
    Inscrit en
    mars 2017
    Messages
    25
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 31
    Localisation : France, Gard (Languedoc Roussillon)

    Informations professionnelles :
    Activité : Développeur Web
    Secteur : High Tech - Multimédia et Internet

    Informations forums :
    Inscription : mars 2017
    Messages : 25
    Points : 18
    Points
    18

    Par défaut

    Merci pour cette explication très complète.

    j'ai modifier pour ouvrir et fermer les connexions juste quand on en avait besoin.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
     
    // Mise à jour du serveur
    MajServeurs();
    // prod
    using (zCnx = new MySqlConnection("Persist Security Info=False;Server=" + zsServeurMySql + ";Database="";Uid="";Pwd=''"))
    {
       zCnx.Open();
       // code ici
       KillConnexion();
    }
    j'ai fais ça pour chaque appel à la base de données.

    Malheureusement, cela n'a pas réglé mon soucis. L'application, une fois fermée reste dans le processus d'arrière plan où seul un peu de mémoire est utilisée.

    Pour le thread, je ne l'instancie qu'une fois au démarrage de l'application :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
     
    private void frm_Chargement_Shown(object sender, EventArgs e)
            {
                //La fenêtre de chargement ne charge que les données nécessaire à l'ouverture de l'application,
                //le reste des données est chargé de façon asynchrone
                Thread t = new Thread(Initialisation);
                t.Start();
                while (t.IsAlive)
                {
                    Application.DoEvents();
                }
                this.Close();
            }
    Est-ce que j'oublie quelque chose ?

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

    Informations professionnelles :
    Activité : .NET / SQL SERVER

    Informations forums :
    Inscription : avril 2007
    Messages : 13 582
    Points : 24 458
    Points
    24 458

    Par défaut

    Citation Envoyé par StringBuilder Voir le message
    Un programme qui reste chargé en sortie est généralement un programme qui ne libère pas convenablement ses ressources.
    Ceci est souvent dû à des instances d'objets IDisposable (faisant appel à des ressources non managées) qui n'ont pas été correctement disposé.
    non

    Citation Envoyé par StringBuilder Voir le message
    la connexion est un objet IDisposable, non managé.
    Cela veut dire que si ton programme sort d'une manière non prévue, alors la connexion ne sera pas libérée.
    non plus

    Citation Envoyé par StringBuilder Voir le message
    Mais cela veut dire aussi que si tu as une coupure réseau, même une micro-coupure, alors la connexion tombe dans un état second et ton programme va à coup sûr mal le gérer et planter... accessoirement en laissant la ressource ouverte.
    ca peut se gérer
    management studio quand on ouvre une fenetre de requete c'est une connection et elle peut rester ouverte des semaines sans problèmes
    même si c'est rarement recommandable avoir une connection pour le temps de l'appli c'est pas forcément dérangeant (si c'est bien fait)

    Citation Envoyé par StringBuilder Voir le message
    Dans l'idéal, on ouvre la connexion au début de chaque traitement, et on la ferme à la fin de chaque traitement.
    oui

    pour info quand tu fermes une connection en .net elle n'est pas fermée
    tout comme le sgbdr fait un pool, .net en fait un aussi et dès que tu demandes une connexion tu en récupères une que .net a gardé



    Citation Envoyé par StringBuilder Voir le message
    Sinon, pour essayer de résoudre ton problème sans tout réécrire, tu peux tenter de rajouter dans tous les Form_Closed de ton application un GC.Collect().
    Mais sans fermer proprement la connexion avant, il y a peu de chances que ça change grand chose (même si au pire ça peut pas faire de mal).
    toujours pas
    une appli se ferme quand tous ses threads sont arrêtés, et quand tous ses threads sont arrêtés elle libère sa mémoire sans problème.
    IDisposable permet normalement d'oublier de disposer vu que le destructeur appelle Dispose



    @virtazp
    il faut ajouter t.IsBackground = true avant de faire t.Start()
    ce qui signifie que ce thread s'arrêtera tout seul quand le thread principal s'arrêtera
    et application.doevents c'est à éviter
    Cours complets, tutos et autres FAQ ici : C# - VB.NET

  5. #5
    Membre à l'essai
    Homme Profil pro
    Développeur Web
    Inscrit en
    mars 2017
    Messages
    25
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 31
    Localisation : France, Gard (Languedoc Roussillon)

    Informations professionnelles :
    Activité : Développeur Web
    Secteur : High Tech - Multimédia et Internet

    Informations forums :
    Inscription : mars 2017
    Messages : 25
    Points : 18
    Points
    18

    Par défaut

    Merci pour vos réponses.

    Ca ne fonctionne pas non plus avec

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
    Thread t = new Thread(Initialisation)
    {
       IsBackground = true,
    };
    Je viens de voir qu'en mode Debug, lorsque je ferme la fenêtre, il faut en plus que je clique sur le bouton stop pour vraiment stopper l'application. Je ne sais pas si cela est lié !

    Si je débug mon programme en cours d’exécution (celui qui reste dans les processus arrière plan), j'ai ce message qui apparaît toutes les minutes environ :

    Le thread 0x1080 s'est arrêté avec le code 0 (0x0).
    Le thread 0x3c38 s'est arrêté avec le code 0 (0x0).
    Le thread 0x1074 s'est arrêté avec le code 0 (0x0).
    Le thread 0x47a4 s'est arrêté avec le code 0 (0x0).
    Le thread 0x4b4c s'est arrêté avec le code 0 (0x0).
    Le thread 0xc14 s'est arrêté avec le code 0 (0x0).
    Le thread 0x217c s'est arrêté avec le code 0 (0x0).
    Le thread 0x4b30 s'est arrêté avec le code 0 (0x0).
    Le thread 0x4608 s'est arrêté avec le code 0 (0x0).
    etc...

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

    Informations professionnelles :
    Activité : .NET / SQL SERVER

    Informations forums :
    Inscription : avril 2007
    Messages : 13 582
    Points : 24 458
    Points
    24 458

    Par défaut

    Le bouton stop arrête tous les threads, il doit t'en rester un en cours qui n'est pas isbackground
    Cours complets, tutos et autres FAQ ici : C# - VB.NET

  7. #7
    Membre à l'essai
    Homme Profil pro
    Développeur Web
    Inscrit en
    mars 2017
    Messages
    25
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 31
    Localisation : France, Gard (Languedoc Roussillon)

    Informations professionnelles :
    Activité : Développeur Web
    Secteur : High Tech - Multimédia et Internet

    Informations forums :
    Inscription : mars 2017
    Messages : 25
    Points : 18
    Points
    18

    Par défaut

    Nom : Capture.PNG
Affichages : 17
Taille : 12,8 Ko

    En regardant, il s'agit d'un travail d'impression ??!!
    Je comprend plus rien.

  8. #8
    Expert confirmé
    Avatar de StringBuilder
    Homme Profil pro
    Chef de projets
    Inscrit en
    février 2010
    Messages
    3 565
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 40
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Chef de projets
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : février 2010
    Messages : 3 565
    Points : 5 964
    Points
    5 964
    Billets dans le blog
    1

    Par défaut

    Effectivement, j'avais oublié le coup du Thread fou qui ne s'arrête pas.

    Par contre, Pol63 je veux bien ta source pour le pool géré côté .NET

    Je ne vois pas comment ni pourquoi ce serait le cas. C'est au SGBD de gérer ça : si .NET crée lui-même un pool local, ça veut dire que des connexions sont ouvertes et restent réservées inutilement côté serveur. Ça n'a pas de sens.


    Pour en revenir au thread fou, dans ton événement FormClosing, il faut que tu fasses un Abort() sur chaque thread.

    Ou plus propre, tu implémentes une méthode "StopPlease()" à tes threads, qui passe à true une variable "shouldStop".
    Tu testes régulièrement cette variable dans la boucle du thread et tu arrêtes ton trairement proprement quand elle passe à true.
    On ne jouit bien que de ce qu’on partage.

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

    Informations professionnelles :
    Activité : .NET / SQL SERVER

    Informations forums :
    Inscription : avril 2007
    Messages : 13 582
    Points : 24 458
    Points
    24 458

    Par défaut

    Citation Envoyé par StringBuilder Voir le message
    Par contre, Pol63 je veux bien ta source pour le pool géré côté .NET
    oui moi aussi ^^, c'est une info qui date dans ma mémoire, je vais rechercher et poster si c'est réellement le cas et que je trouve

    Citation Envoyé par StringBuilder Voir le message
    Pour en revenir au thread fou, dans ton événement FormClosing, il faut que tu fasses un Abort() sur chaque thread.
    un thread ne peut être fou, le code ne fait que ce qu'on lui dit
    et faire .abort sur un thread est aussi conseillé que de garder une connexion sql ouverte je pense
    Cours complets, tutos et autres FAQ ici : C# - VB.NET

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

    Informations professionnelles :
    Activité : .NET / SQL SERVER

    Informations forums :
    Inscription : avril 2007
    Messages : 13 582
    Points : 24 458
    Points
    24 458

    Par défaut

    trouvé ça https://docs.microsoft.com/fr-fr/dot...tframework-4.8
    et j'ai jeté un œil vite fait au code source de SqlConnection j'ai trouvé des options de pooling

    après c'est pas forcément dérangeant, surtout si c'est paramétrable
    Cours complets, tutos et autres FAQ ici : C# - VB.NET

  11. #11
    Expert confirmé
    Avatar de StringBuilder
    Homme Profil pro
    Chef de projets
    Inscrit en
    février 2010
    Messages
    3 565
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 40
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Chef de projets
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : février 2010
    Messages : 3 565
    Points : 5 964
    Points
    5 964
    Billets dans le blog
    1

    Par défaut

    J'avoue que l'article me laisse un peu perplexe...

    Il est avant tout question de ADO.NET plutôt que du framework .NET lui-même.

    Et aussi, il n'est fait mention que de SQL Server.

    J'ai l'impression qu'on parle bien ici du pooling de connexion SQL Server, vu à travers la couche ADO.NET.

    Car dans tous les cas, dans une application cliente multi poste qui accèderait à une base de données unique, un pooling côté client serait tout sauf bénéfique.
    On ne jouit bien que de ce qu’on partage.

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

    Informations professionnelles :
    Activité : .NET / SQL SERVER

    Informations forums :
    Inscription : avril 2007
    Messages : 13 582
    Points : 24 458
    Points
    24 458

    Par défaut

    ado.net fait parti du Framework .net je pense, c'est le morceau qui gère l'accès au données, comme wcf est le morceau qui gère des webservices et winform/wpf des morceaux graphiques du framework
    je pense que dans toute appli ça peut être bénéfique de gagner du temps, les connections tcp (ou autre) ouvertes je ne sais pas si c'est dommageable, sur quoi d'autre a pourrait être négatif ?

    (...)

    j'ai rejeté un oeil sur le code source, et y a quand même pas mal de truc qui parlent de pooling, le sqlconnetion a un innerconnetion, et y a une classe DbConnectionPool au milieu de tout ça
    selon moi le pool de connection côté sgbdr doit être indépendant du client, donc ne devrait pas représenter de code dans une api cliente
    et le pool côté sgbdr ce n'est pas une connection tcp qu'il garde, mais un contexte d'exécution je pense
    Cours complets, tutos et autres FAQ ici : C# - VB.NET

  13. #13
    Membre à l'essai
    Homme Profil pro
    Développeur Web
    Inscrit en
    mars 2017
    Messages
    25
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 31
    Localisation : France, Gard (Languedoc Roussillon)

    Informations professionnelles :
    Activité : Développeur Web
    Secteur : High Tech - Multimédia et Internet

    Informations forums :
    Inscription : mars 2017
    Messages : 25
    Points : 18
    Points
    18

    Par défaut

    Re

    Je pense que cela vient de l'utilisation de
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    Application.DoEvents();
    J'ai vu sur forum que cela génère des bugs, si on n'a pas vraiment compris son utilisation.

    Le soucis, c'est que c'est pas moi qui est codé cette application, et on est en train de me mettre la pression pour trouvé ^^ .

    Du coup ce matin, j'ai inséré dans la méthode dispose du formulaire principal

    et ça tue bien tout les threads. Mais j'avoue que c'est pas très propre, il y a bien un soucis ailleurs.

    Je ne met pas la discussion en résolue car je ne fait que contourner le problème et je vais chercher pourquoi, je reviendrai compléter le fil.

    Mais merci beaucoup pour votre participation, et n'hésitez pas à me dire si vous comprenez pourquoi

  14. #14
    Expert confirmé
    Avatar de StringBuilder
    Homme Profil pro
    Chef de projets
    Inscrit en
    février 2010
    Messages
    3 565
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 40
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Chef de projets
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : février 2010
    Messages : 3 565
    Points : 5 964
    Points
    5 964
    Billets dans le blog
    1

    Par défaut

    Il faudrait surtout savoir :
    - Ce que fait ton thread
    - S'il se termine tout seul avant la fermeture du programme
    - Si le process reste en mémoire jusqu'à ce que le thread soit terminé ou si ça continue encore après

    Ensuite, le while isalive + doevents, c'est juste crade.
    Que fait le thread (une fois de plus), et pourquoi est-ce en thread ?
    Habituellement, le doevents sert justement à traiter les événements de la GUI à l'intérieur d'une boucle dans le thread principal.
    Un Sleep(10) à la place du doevents ne sera que bénéfique.

    Mais je ne vois pas trop l'intérêt d'attendre la fin du thread dans une boucle qui ne fait rien surtout...
    On ne jouit bien que de ce qu’on partage.

  15. #15
    Expert confirmé
    Avatar de StringBuilder
    Homme Profil pro
    Chef de projets
    Inscrit en
    février 2010
    Messages
    3 565
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 40
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Chef de projets
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : février 2010
    Messages : 3 565
    Points : 5 964
    Points
    5 964
    Billets dans le blog
    1

    Par défaut

    Citation Envoyé par Pol63 Voir le message
    selon moi le pool de connection côté sgbdr doit être indépendant du client, donc ne devrait pas représenter de code dans une api cliente
    et le pool côté sgbdr ce n'est pas une connection tcp qu'il garde, mais un contexte d'exécution je pense
    Ok pour le pool de connections TCP.
    Mais ça semble quand même étonnant car dans l'article il est bien précisé que le contexte côté serveur jour un rôle : si on est en SSPI alors le pooling ne peut pas réutiliser les connections du pool : si ça ne touche qu'à TCP, rien ne justifie ce comportement.

    Après, ce pooling existe et fonctionne de la même manière et avec les mêmes options avec le pilote ODBC ou OLEDB.
    Je me demande donc si c'est pas simplement une extension côté client du pooling côté serveur afin de modifier son comportement.
    On ne jouit bien que de ce qu’on partage.

  16. #16
    Expert confirmé
    Avatar de StringBuilder
    Homme Profil pro
    Chef de projets
    Inscrit en
    février 2010
    Messages
    3 565
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 40
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Chef de projets
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : février 2010
    Messages : 3 565
    Points : 5 964
    Points
    5 964
    Billets dans le blog
    1

    Par défaut

    Un petit exemple complet de gestion propre de l'arrêt du thread :
    Code csharp : 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
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
     
    using System;
    using System.Threading;
    using System.Windows.Forms;
     
    namespace TestThread
    {
        public partial class FrmMain : Form
        {
            Worker worker;
            Thread workerThread;
     
            public FrmMain()
            {
                InitializeComponent();
                progressBar1.Minimum = 0;
                progressBar1.Maximum = 100;
            }
     
            private void FrmMain_Load(object sender, EventArgs e)
            {
                worker = new Worker();
                worker.ProgressChanged += new EventHandler<ProgressChangedArgs>(OnWorkerProgressChanged);
                workerThread = new Thread(new ThreadStart(worker.StartWork));
                workerThread.Start();
                // Et on laisse le thread vivre dans son coin
            }
     
            private void OnWorkerProgressChanged(object sender, ProgressChangedArgs e)
            {
                if (this.InvokeRequired)
                {
                    this.BeginInvoke((MethodInvoker)delegate
                    {
                        OnWorkerProgressChanged(sender, e);
                    });
                    return;
                }
     
                progressBar1.Value = e.Progress;
            }
     
            private void FrmMain_FormClosing(object sender, FormClosingEventArgs e)
            {
                worker.ShouldStop = true;
                workerThread.Join();
            }
        }
     
        public class Worker
        {
            public bool ShouldStop { get; set; } = false;
     
            public event EventHandler<ProgressChangedArgs> ProgressChanged;
     
            protected void OnProgressChanged(ProgressChangedArgs e)
            {
                ProgressChanged?.Invoke(this, e);
            }
     
            public void StartWork()
            {
                int i;
                for (i = 0; i < 100 && !ShouldStop; i++)
                {
                    OnProgressChanged(new ProgressChangedArgs(i));
                    Thread.Sleep(100);
                }
                OnProgressChanged(new ProgressChangedArgs(i));
            }
        }
     
        public class ProgressChangedArgs : EventArgs
        {
            public int Progress { get; private set; }
            public ProgressChangedArgs(int progress)
            {
                Progress = progress;
            }
        }
    }

    Tant que la progressbar n'est pas arrivée au bout, le thread tourne.
    Si tu vires le code dans form_closing, alors le programme reste ouvert après fermeture de la fenêtre tant que le thread n'a pas terminé.
    Si tu laisses le form_closing tel quel, on indique au thread qu'on veut qu'il s'arrête. Et à ce moment le programme s'arrête en même temps que la fermeture de la fenêtre (tout du moins, dès que le thread rend la main, aussitôt qu'il détecte qu'on veut qu'il s'arrête.

    Moi je vois bien que ton thread doit faire un joli while(true) sans condition de sortie... et donc ne s'arrête que si on le kill.

    Tu noteras qu'après démarrage du thread, je le laisse vivre dans son coin : pas la peine de mettre un doevents ou quelque boucle que ce soit.
    Aussi, après le passage de shouldstop à true, je fait un thread.Join() : ceci permet de bloquer la fermeture de la fenêtre tant que le thread n'a pas fini.
    Ça peut être utile si le thread doit interagir avec la form avant de s'arrêter.

    PS : J'ai eu beaucoup de mal pour retrouver de la doc et des exemples pour faire ce code. Cette gestion des thread date de .NET < 2.0

    Depuis, on passe plutôt par des BackgroundWorker, plus simples à utiliser.

    Et depuis la version 4.0 on ne déclare plus les thread explicitement : async et await font le job à la place (même si en soit il y a certaines différentes qui peuvent encore nécessiter l'utilisation de thread à la main).
    On ne jouit bien que de ce qu’on partage.

Discussions similaires

  1. [XL-2010] Propriété qui met le chart à l'arrière plan?
    Par Gualino dans le forum Macros et VBA Excel
    Réponses: 6
    Dernier message: 06/10/2011, 18h29
  2. Lancer un processus en arrière-plan
    Par Morgan7469 dans le forum C#
    Réponses: 10
    Dernier message: 17/03/2011, 14h48
  3. Changer la priorité des processus d'arrière plan Oracle
    Par dcollart dans le forum Administration
    Réponses: 1
    Dernier message: 16/07/2010, 15h22
  4. Lancer sous la console dos un processus en arrière plan.
    Par ziad.shady dans le forum Scripts/Batch
    Réponses: 6
    Dernier message: 25/10/2009, 14h44
  5. Lancer des processus en arrière plan
    Par momeftah dans le forum Shell et commandes GNU
    Réponses: 11
    Dernier message: 01/05/2007, 18h50

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