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

C# Discussion :

Evénements, multi-threading & simplicité


Sujet :

C#

  1. #1
    Nouveau Candidat au Club
    Inscrit en
    Mars 2009
    Messages
    2
    Détails du profil
    Informations forums :
    Inscription : Mars 2009
    Messages : 2
    Points : 1
    Points
    1
    Par défaut Evénements, multi-threading & simplicité
    Bonjour à tous !

    Je suis en train de développer un objet qui permet de créer un serveur TCP multi-clients.
    Cette object contient quelques thread ainsi que des evenements (OnNewConnection, OnNewMessage…).

    Pour illustrer mon problème, imaginons un objet nommé classServer qui lance un thread au moment de son instanciation. Ce thread fait appel à la méthode ThreadListen qui attend la connexion d’un nouveau client sur un port donné. Lorsqu’un nouveau client se connecte, l’événement OnNewClient est déclenché.

    Voici donc un code très simplifié mais fonctionnel de cet objet :

    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
     
        class classServer
        {
            public delegate void NewClientEventHandler(object sender, EventArgs e);
            public event NewClientEventHandler OnNewClient;
            Thread MyThread;
     
            public classServer()
            {
                MyThread = new Thread(ThreadListen);
                MyThread.Start();
            }
     
            private void ThreadListen()
            {
                while(true)
                {
                    Thread.Sleep(1000); //attente d’une nouvelle connexion
                    if (OnNewClient != null)
                        OnNewClient(this, new EventArgs());
                }
            }
        }
    Si nous désirons utiliser cet objet tel quel et afficher la phrase « nouveau client » dans une textbox lorsque l’événement OnNewClient a lieu, voici le code que nous allons devoir mettre en place :

    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
     
        public partial class Form1 : Form
        {
            classServer MyServer;
            private delegate void AjoutTextBox1Text(string p_text);
     
            private void AjoutTextBox1(string p_text)
            {
                textBox1.Text = p_text;
            }
     
            public Form1()
            {
                InitializeComponent();
                MyServer = new classServer();
                MyServer.OnNewClient += new classServer.NewClientEventHandler(MyServer_OnNewClient);
            }
     
            void MyServer_OnNewClient(object sender, EventArgs e)
            {
                AjoutTextBox1Text AjoutText = new AjoutTextBox1Text(AjoutTextBox1);
                Invoke(AjoutText, new object[] { (object)"Nouveau client" });
            }
        }
    Je trouve ce code vraiment lourd est je préfèrerais largement qu’il ressemble à quelque chose comme 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
     
        public partial class Form1 : Form
        {
            classServer MyServer;
     
            public Form1()
            {
                InitializeComponent();
                MyServer = new classServer();
                MyServer.OnNewClient += new classServer.NewClientEventHandler(MyServer_OnNewClient);
            }
     
            void MyServer_OnNewClient(object sender, EventArgs e)
            {
                textBox1.Text = "Nouveau client";
            }
        }
    Evidement, ce code est impossible. Au moment de mettre à jour notre textbox, le CLR va gentiment nous préciser que nous désirons réaliser une opération entre 2 thread, que ce n’est pas bien et qu’il refuse de faire une telle chose.

    Pourtant, j’aimerais beaucoup que mon objet soit utilisable de cette manière. Y’aurait-il un moyen de modifier mon objet classServer de manière à le rendre plus simple d’utilisation?

    Si vous avez LA solution ou ne serait-ce qu'une piste, je suis preneur !

    Merci

  2. #2
    Expert éminent
    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 : 46
    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
    Points : 7 660
    Points
    7 660
    Par défaut
    Soit tu restes sur le principe d'une méthode spécifique, en faisant plutôt ceci
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    private delegate void SetTextCallBack(string text);
    private void SetText(string text)
    {
        if (this.InvokeRequired)
        {
            this.Invoke(new SetTextCallBack(SetText), text);
        }
        else
        {
            maTextBox.Text = Text;
        }
    }
    Simplifiant ainsi l'appel puisque la méthode se charge elle même de l'invocation.

    Soit tu regardes du côté des classes AsyncOperationManager et AsyncOperation, classes utilisées notamment par le BackGroundWorker pour les opérations asynchrones
    Pas de questions techniques par MP

  3. #3
    Nouveau Candidat au Club
    Inscrit en
    Mars 2009
    Messages
    2
    Détails du profil
    Informations forums :
    Inscription : Mars 2009
    Messages : 2
    Points : 1
    Points
    1
    Par défaut
    Merci pour ta réponse.

    Combiner les 2 méthodes en une seule me semble effectivement plus joli.

    Je vais me pencher sur les classes AsyncOperationManager et AsyncOperation.

    Pour ce qui est de BackGroundWorker, je ne connais pas trop cet outil, mais je me demande si dans mon cas l’utilisation d’un tel outil ne relèverait pas la « bidouille ». Mais je vais voir quand même.

  4. #4
    Rédacteur/Modérateur


    Homme Profil pro
    Développeur .NET
    Inscrit en
    Février 2004
    Messages
    19 875
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 42
    Localisation : France, Paris (Île de France)

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

    Informations forums :
    Inscription : Février 2004
    Messages : 19 875
    Points : 39 749
    Points
    39 749
    Par défaut
    il y a un tuto sur MSDN pour faire ça :
    http://msdn.microsoft.com/fr-fr/library/bz33kx67.aspx

  5. #5
    Nouveau Candidat au Club
    Inscrit en
    Décembre 2007
    Messages
    1
    Détails du profil
    Informations forums :
    Inscription : Décembre 2007
    Messages : 1
    Points : 1
    Points
    1
    Par défaut utiliser un textbox dans un thread
    mon code est constitué de 2thread qui doivent utiliser des textbox, et jutilise la meme procédure que kizab i.e à peu prés ça:
    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 partial class Form1 : Form
        {
            classServer MyServer;
            private delegate void AjoutTextBox1Text(string p_text);
     
            private void AjoutTextBox1(string p_text)
            {
                textBox1.Text = p_text;
            }
     
            public Form1()
            {
                InitializeComponent();
                MyServer = new classServer();
                MyServer.OnNewClient += new classServer.NewClientEventHandler(MyServer_OnNewClient);
            }
     
            void MyServer_OnNewClient(object sender, EventArgs e)
            {
                AjoutTextBox1Text AjoutText = new AjoutTextBox1Text(AjoutTextBox1);
                Invoke(AjoutText, new object[] { (object)"Nouveau client" });
            }
        }
    j'ai aussi essayé de comprendre comment utiliser le AsyncOperationManager mais j'ai pas bien saisi le principe de leur utilisation,et en quoi ça peut m'aider pour ne pas avoir l'exception généré par le Invoke?
    merci

  6. #6
    Expert éminent
    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 : 46
    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
    Points : 7 660
    Points
    7 660
    Par défaut
    Citation Envoyé par lindsay Voir le message
    j'ai aussi essayé de comprendre comment utiliser le AsyncOperationManager mais j'ai pas bien saisi le principe de leur utilisation,et en quoi ça peut m'aider pour ne pas avoir l'exception généré par le Invoke?
    merci
    Il suffit de lire la MSDN
    Si votre classe doit fournir un comportement asynchrone en fonction du Vue d'ensemble du modèle asynchrone basé sur des événements, vous rencontrerez un certain nombre de problèmes liés à la gestion de l'accès concurrentiel. Un de ces problèmes est de garantir que les gestionnaires d'événements sont appelés sur un thread ou un contexte qui est approprié pour le modèle d'application (par exemple, les applications Windows Forms, les applications ASP.NET, les applications console, etc.). AsyncOperationManager offre un moyen pratique de créer une classe qui s'exécute correctement sur tous les modèles d'application pris en charge par le .NET Framework.
    Et le BackgroundWorker utilise cette classe justement.
    Pas de questions techniques par MP

  7. #7
    Nouveau membre du Club
    Profil pro
    Étudiant
    Inscrit en
    Décembre 2007
    Messages
    33
    Détails du profil
    Informations personnelles :
    Localisation : Algérie

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Décembre 2007
    Messages : 33
    Points : 33
    Points
    33
    Par défaut
    pour permettre les operations entre 2 threads
    essay de faire :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
     CheckForIllegalCrossThreadCalls = false;

  8. #8
    Rédacteur/Modérateur


    Homme Profil pro
    Développeur .NET
    Inscrit en
    Février 2004
    Messages
    19 875
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 42
    Localisation : France, Paris (Île de France)

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

    Informations forums :
    Inscription : Février 2004
    Messages : 19 875
    Points : 39 749
    Points
    39 749
    Par défaut
    Citation Envoyé par zakizaki7 Voir le message
    pour permettre les operations entre 2 threads
    essay de faire :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
     CheckForIllegalCrossThreadCalls = false;
    TRES fortement déconseillé...

    S'il y a cette vérification des appels cross-threads, c'est parce qu'un appel cross-thread peut avoir des conséquences imprévues. Et comme c'est imprévu, on n'est pas sûr de voir le problème pendant le développement, il peut se produire un peu n'importe quand... L'exception qui est systématiquement levée quand on essaie de faire un appel cross-thread est un "signal d'alarme" du framework pour dire au développeur "attention, c'est dangereux ce que tu fais...". Désactiver ce "garde-fou" revient à arrêter l'alarme à incendie sans éteindre le feu

  9. #9
    Expert éminent
    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 : 46
    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
    Points : 7 660
    Points
    7 660
    Par défaut
    Citation Envoyé par zakizaki7 Voir le message
    pour permettre les operations entre 2 threads
    essay de faire :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
     CheckForIllegalCrossThreadCalls = false;


    Cette propriété peut être utilisée en phase de débogage afin de faciliter la recherche d'erreur par exemple, mais c'est tout ! Cf. MSDN

    Affectez true à CheckForIllegalCrossThreadCalls pour faciliter la recherche et le diagnostic de cette activité de thread pendant le débogage. Notez que les appels inter-threads illégaux déclenchent toujours une exception lorsqu'une application est démarrée en dehors du débogueur.
    Pas de questions techniques par MP

  10. #10
    Rédacteur/Modérateur


    Homme Profil pro
    Développeur .NET
    Inscrit en
    Février 2004
    Messages
    19 875
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 42
    Localisation : France, Paris (Île de France)

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

    Informations forums :
    Inscription : Février 2004
    Messages : 19 875
    Points : 39 749
    Points
    39 749
    Par défaut
    Affectez true à CheckForIllegalCrossThreadCalls pour faciliter la recherche et le diagnostic de cette activité de thread pendant le débogage. Notez que les appels inter-threads illégaux déclenchent toujours une exception lorsqu'une application est démarrée en dehors du débogueur.
    Ah ben c'est encore pire que je croyais alors

Discussions similaires

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

Partager

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