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 :

Zone critique pour 2 threads


Sujet :

Windows Forms

  1. #1
    Membre éclairé Avatar de TrEiZe85
    Inscrit en
    Février 2007
    Messages
    82
    Détails du profil
    Informations personnelles :
    Âge : 39

    Informations forums :
    Inscription : Février 2007
    Messages : 82
    Par défaut Zone critique pour 2 threads
    Petite explication :

    J'ai une application WinForm qui permet de consulter et de modifier les données d'une BDD MySql. Cette base de donnée est mise a jour grace à l'importation journaliere d'un fichier XML. Jusqu'ici rien de bien sorcier !

    Je voudrais pouvoir afficher le contenu de la base de données cela pendant l'importation de mon fichier XML. J'ai donc créer deux threads :

    threadListemat => pour la partie importation XML
    threadAffichage => Pour la partie affichage

    Seul probleme lorsque j'execute le threadAffichage pendant l'execution du threadListemat des erreurs apparaissent dues à la lecture/ecriture simultanée dans ma base de données...

    Il faudrait donc que je puisse bloquer l'acces en lecture/ecriture à ma BDD à un seul et unique thread....

    J'ai tenté l'utilisation du lock(this) ainsi que la suspension de mon thread (thread.Suspend())

    Comment empecher mon threadAffichage d'acceder à cette zone critique MySql en meme temps que le threadListemat ????

    Si vous voulez plus de precision ou des morceaux de mon code n'hesitez pas à demander !!!

    Merci de vos futures reponses !

  2. #2
    Membre expérimenté
    Avatar de StormimOn
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Mai 2005
    Messages
    2 593
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 47
    Localisation : France, Sarthe (Pays de la Loire)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Mai 2005
    Messages : 2 593
    Par défaut
    Quand tu dis que tu as tenté d'utiliser le lock, pourrais-tu préciser ?

    Comment as-tu procédé et qu'est ce qui n'allait pas ? Car à priori ca n'a pas fonctionné

  3. #3
    Membre éclairé Avatar de TrEiZe85
    Inscrit en
    Février 2007
    Messages
    82
    Détails du profil
    Informations personnelles :
    Âge : 39

    Informations forums :
    Inscription : Février 2007
    Messages : 82
    Par défaut
    J'ai fait un lock(this) qui englobe les methodes d'acces a la BDD...

    Faut il que je lock toute ma classe ??? Est ce possible ???

    Merci de ta rep

  4. #4
    Membre expérimenté
    Avatar de StormimOn
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Mai 2005
    Messages
    2 593
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 47
    Localisation : France, Sarthe (Pays de la Loire)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Mai 2005
    Messages : 2 593
    Par défaut
    Le lock(this) est a éviter en général. Il est plutôt conseillé de déclarer une variable privée pour ca, statique ou non, suivant que la zone critique soit valable pour une seule ou plusieurs instances.

    Un exemple comme un autre de l'utilisation du lock
    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
    class ClassTestThread
    {
        private static object verrou = new object();
     
        private string _texte;
        private AutoResetEvent _reset;
     
        public ClassTestThread(string texte, AutoResetEvent reset)
        {
            _texte = texte;
            _reset = reset;
        }
     
        public void Start()
        {
            ThreadPool.QueueUserWorkItem(Traitement);
        }
     
        private void Traitement(object state)
        {
            lock (verrou)
            {
                for (int i = 0; i < 10; i++)
                {
                    Console.WriteLine(_texte + " : " + i);
                    Thread.Sleep(new Random().Next(100, 2000));
                }
            }
     
            _reset.Set();
        }
    }
    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
    class Program
    {
        static void Main(string[] args)
        {
            AutoResetEvent[] resets = new AutoResetEvent[] { new AutoResetEvent(false), new AutoResetEvent(false) };
     
            ClassTestThread test1 = new ClassTestThread("Thread 1", resets[0]);
            ClassTestThread test2 = new ClassTestThread("Thread 2", resets[1]);
     
            test1.Start();
            test2.Start();
     
            WaitHandle.WaitAll(resets);
     
            Console.ReadLine();
        }
    }
    Si jamais tu utilisais lock(this) dans ce cas, le comportement ne serait plus celui attendu, à savoir que rien ne garanti que le premier thread ai fini avant que le second ne commence l'affichage.

  5. #5
    Membre éclairé Avatar de TrEiZe85
    Inscrit en
    Février 2007
    Messages
    82
    Détails du profil
    Informations personnelles :
    Âge : 39

    Informations forums :
    Inscription : Février 2007
    Messages : 82
    Par défaut
    Merci de ta reponse

    De mon coté je n'utilise pas une classe Thread comme ClassTestThread dans ton exemple....

    Voici une partie de mon code :

    Chargement de mon IHM et creation des 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
     
    private void Form1_Load(object sender, EventArgs e)
            {
                dataGridView1.DataSource = null;
                DataSetBDD.Clear();
                dataGridView1.AutoGenerateColumns = false;
     
                monThread = new Thread(new ThreadStart(démarrageServeur));
                threadListemat=new Thread(new ThreadStart(importXml));
                threadProgressBar=new Thread(new ThreadStart(progressBar));
                threadProgressBarStart=new Thread(new ThreadStart(progressBarStart));
                threadAffichage=new Thread(new ThreadStart(affichageBDD));            
     
                monThread.IsBackground = true;
    			threadProgressBar.IsBackground = true;
                threadListemat.IsBackground = true;  
                threadProgressBarStart.IsBackground = true;
    			threadAffichage.IsBackground = true;
     
    			monThread.Start();
    			threadAffichage.Start();
                dataGridView1.Visible = true;
            }
    Code executé par le thread listemat
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
     
            private void importXml()
            {         
                this.Invoke(new setTexteStatusBarre(texteStatusBarre), "Etat : Verification fichier listemat.XML");
                gestionExcel.importerFichierXML("listemat.xml");
                this.Invoke(new setTexteStatusBarre(texteStatusBarre), "Etat : Xml importé");
                threadListemat.Abort();
            }
    Code executé par le thread affichage
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
     
        public void affichageBDD()
            {        	
            	while(gestionBDD.getEtatConnection()=="Open")
            	{
            	}
            	this.Invoke(new setAffichage(gestionBDD.affichageBDD),"*","");
            	threadAffichage.Abort();
            }
    methode contenant la zone critique :
    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
     
           public void insertionBDD(string requeteInsert)
            {
                this.requeteInsert = requeteInsert;
     
                connexionBDD();
     
                MySqlCommand Insert = new MySqlCommand(requeteInsert, Connection);
     
                lock(this)
                {          	
                    try
                	{
                    	Insert.ExecuteNonQuery();
                	}
                	catch (MySqlException e)
                	{
                    	MessageBox.Show(e.Message);                
                	}
    			}
                deconnexionBDD();
     
            }

    Je veut donc que le thread affichage s'execute seulement lorsque le thread listemat ne communique pas avec ma base....

  6. #6
    Membre expérimenté
    Avatar de StormimOn
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Mai 2005
    Messages
    2 593
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 47
    Localisation : France, Sarthe (Pays de la Loire)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Mai 2005
    Messages : 2 593
    Par défaut
    En fait les threads en question ne tournent pas en "boucle", ils ne s'exécutent qu'une seule fois chacun, on peut faire plus simple en bloquant le second thread tant que le premier n'a pas fini à ce moment, ca devrait suffir, sauf si il y a autre chose derrière dont tu n'as pas parlé ^^

    Dans cet exemple, le thread d'affichage ne pourra démarrer qu'une fois celui de l'import terminé.
    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
    public partial class Form1 : Form
    {
        private AutoResetEvent _resetEvent;
     
        public Form1()
        {
            InitializeComponent();
     
            _resetEvent = new AutoResetEvent(false);
        }
     
        private void Form1_Load(object sender, EventArgs e)
        {
            ThreadPool.QueueUserWorkItem(Affichage);
            ThreadPool.QueueUserWorkItem(Import);
        }
     
        private void Import(object state)
        {
            // Traitement d'import
            MessageBox.Show("Import en cours ...");
            // On signale l'événement pour débloquer le thread d'affichage
            _resetEvent.Set();
        }
     
        private void Affichage(object state)
        {
            // Attends la fin du thread d'import
            _resetEvent.WaitOne();
            // Traitement de l'affichage
            MessageBox.Show("Affichage en cours ...");
        }
    }

  7. #7
    Membre éclairé Avatar de TrEiZe85
    Inscrit en
    Février 2007
    Messages
    82
    Détails du profil
    Informations personnelles :
    Âge : 39

    Informations forums :
    Inscription : Février 2007
    Messages : 82
    Par défaut
    Merci de te pencher sur mon probleme je teste des demain matin au boulot. Je pense que le code si dessus va repondre à mon probleme ! Je repost si ca ne convient pas ou si j'ai de nouveaux problemes sur ce sujet !

    Merci encore !

  8. #8
    Membre expérimenté
    Avatar de StormimOn
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Mai 2005
    Messages
    2 593
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 47
    Localisation : France, Sarthe (Pays de la Loire)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Mai 2005
    Messages : 2 593
    Par défaut
    Je viens de me relire et soit j'ai mal compris ton problème, et j'ai répondu en restant sur 2 threads, soit pourquoi tu ne lances pas simplement un seul thread dans lequel tu lis ton XML pour mettre à jour ta base et ensuite tu gère l'affichage.

  9. #9
    Membre éclairé Avatar de TrEiZe85
    Inscrit en
    Février 2007
    Messages
    82
    Détails du profil
    Informations personnelles :
    Âge : 39

    Informations forums :
    Inscription : Février 2007
    Messages : 82
    Par défaut
    En fait pendant l'importationn, l'utilisateur à la possibilité de cliquer dans un menu sur afficherBDD ou rechercherBDD.... Ce qui entraine un acces "conccurent" à ma base de données...

    Je voudrais que le thread affichage attende la fin d'une insertion du thread listemat pour ensuite le stopper (ou le mettre en pause) puis s'executer lui meme.

    1 -threadListemat ==> n+1 insertion
    2- threadAffichage attend fin d'1 insertion
    3- threadListemat se met en attente
    4- threadAffichage demarre
    5- threadAffichage affiche le contenu de la BDD
    6- fin threadAffichage
    7- reprise du threadListemat

  10. #10
    Membre expérimenté
    Avatar de StormimOn
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Mai 2005
    Messages
    2 593
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 47
    Localisation : France, Sarthe (Pays de la Loire)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Mai 2005
    Messages : 2 593
    Par défaut
    Juste en passant, pas trop le temps ce midi, ni ce soir normallement, de me repencher sur la question, mais dans ton exemple de code où tu utilises le lock, il y a un petit souci à la base, je devais avoir la tête dans le cul quand j'ai regardé la première fois pour passer à côté.

    En faisant ceci
    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
    public void insertionBDD(string requeteInsert)
    {
        this.requeteInsert = requeteInsert;    
        connexionBDD();    
        MySqlCommand Insert = new MySqlCommand(requeteInsert, Connection);
     
        lock(this)
        {          	
            try
            {
              	Insert.ExecuteNonQuery();
            }
            catch (MySqlException e)
            {
              	MessageBox.Show(e.Message);                
            }
        }
       deconnexionBDD();      
    }
    tu ne protèges pas la connexion à ta base de données (ni la déconnexion d'ailleurs) et ta requête. Je ne pense pas que ce soit lié à ton problème, c'est juste une remarque que j'aurai du faire avant si j'avais bien regardé. Corrige donc cette zone

    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
    public void insertionBDD(string requeteInsert)
    {
        lock(this)
        {          	
            this.requeteInsert = requeteInsert;    
            connexionBDD();    
            MySqlCommand Insert = new MySqlCommand(requeteInsert, Connection);
     
            try
            {
              	Insert.ExecuteNonQuery();
            }
            catch (MySqlException e)
            {
              	MessageBox.Show(e.Message);                
            }
     
            deconnexionBDD();      
        }
    }

  11. #11
    Membre éclairé Avatar de TrEiZe85
    Inscrit en
    Février 2007
    Messages
    82
    Détails du profil
    Informations personnelles :
    Âge : 39

    Informations forums :
    Inscription : Février 2007
    Messages : 82
    Par défaut
    Tout d'abord mer ci de t'etre penché sur mon probleme ! Qui persiste toujours d'ailleurs.....

    J'ai fait une petite bidouille qui permet de locker en quelque sorte l'acces simultané à ma base, voici ce que ca donne :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
           	        while(gestionBDD.getEtatConnection()=="Open")
            	{
            	}
            	this.Invoke(new setAffichage(gestionBDD.affichageBDD),"*","");
            	threadAffichage.Abort();
    Existe t'il une methode MySql qui permet de mettre en attente une requete ? ou tout simplement d'effectuer une requerte multiple...

    Je me posait la questiob suivante : ne serait t'il pas plus simple de tester entre chaque requete si une demande d'affichage est en cours (thread.isalive=true), je crois que je m'embrouille tout seul ! lol Je vais passer ma journée dessus, si ca ne passe pas je reovis tout mon systame de thread depuis le debut....

  12. #12
    Expert confirmé

    Homme Profil pro
    Chef de projet NTIC
    Inscrit en
    Septembre 2006
    Messages
    3 580
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : Chef de projet NTIC
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Septembre 2006
    Messages : 3 580
    Par défaut
    bonjour

    J'ai eu à gérer un problème un peu équivalent il y a quelques temps...

    La solution que nous avons adopté est la suivante :

    Quand un process ou un batch se lance pour mettre à jour des tables
    de la base de données, nous remplissons une information dans une table
    de la base nous indiquant qu'un traitement "de type batch" est en cours.

    Ainsi, nous nous protegeons contre des accès "concurrentiels" à un moment
    non souhaité du cycle de mise à jour de la base de données

    J'aurais tendance à "interdire" à l'utilisateur certaines actions tant que la
    base est en phase de mise à jour...

    Cette approche à l'avantage de s'expliquer "facilement" au client, et d'etre
    beaucoup moins compliquée à implémenter, à tester et à valider...

    The Monz, Toulouse

  13. #13
    Membre éclairé Avatar de TrEiZe85
    Inscrit en
    Février 2007
    Messages
    82
    Détails du profil
    Informations personnelles :
    Âge : 39

    Informations forums :
    Inscription : Février 2007
    Messages : 82
    Par défaut
    Le seul probleme est que cette importation met environ 5-6 minutes à s'effectuer je ne peu donc pas faire patienter l'utilisateur pendant tout ce temps !

  14. #14
    Membre éclairé Avatar de TrEiZe85
    Inscrit en
    Février 2007
    Messages
    82
    Détails du profil
    Informations personnelles :
    Âge : 39

    Informations forums :
    Inscription : Février 2007
    Messages : 82
    Par défaut
    Merci StormimOn pour tes reponses ! l'utilisation du _resetEvent.set() et _resetEvent.WaitOne() vont me permettre de liberer l'acces a la zone critique !

    Je poste le code propre de la reponse d'ici demain en reponse

Discussions similaires

  1. Aide pour un thread (debutant)
    Par koolkris dans le forum Delphi
    Réponses: 2
    Dernier message: 02/04/2007, 20h45
  2. Je n'arrive pas à faire sans stop() pour un thread
    Par PaladinFr dans le forum Concurrence et multi-thread
    Réponses: 2
    Dernier message: 15/03/2007, 15h37
  3. Critiques pour livre
    Par aure-sky dans le forum Flash
    Réponses: 1
    Dernier message: 04/02/2007, 00h22
  4. Librairie OO et portable pour RegExp, Thread, Sockets, etc..
    Par Swoög dans le forum Bibliothèques
    Réponses: 29
    Dernier message: 27/05/2006, 13h29

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