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 :

Partage d'une List<T> entre Thread


Sujet :

C#

  1. #1
    Candidat au Club
    Femme Profil pro
    Enseignant
    Inscrit en
    Mars 2017
    Messages
    4
    Détails du profil
    Informations personnelles :
    Sexe : Femme
    Localisation : Belgique

    Informations professionnelles :
    Activité : Enseignant
    Secteur : Enseignement

    Informations forums :
    Inscription : Mars 2017
    Messages : 4
    Points : 2
    Points
    2
    Par défaut Partage d'une List<T> entre Thread
    Bonjour,

    Je tente de coder un programme qui utilisera plusieurs thread :

    - Un mettra à jour une liste (ajout/suppression d'éléments) selon des message reçu par des providers
    - Un effectuera la communication avec un client et devra pouvoir généré un message à partir de la liste

    Pour l'instant je génère la liste manuellement (je m'occuperais de la discussion avec les providers plus tard).
    La discussion avec le client fonctionne sans problème si je n'utilise pas la liste (je génère manuellement un string à la place).

    Mon problème est que le thread du client parviennent à lire la liste.

    Mon Main est le suivant :
    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
    static void Main(string[] args)
            {
                List<Provider> providerList = new List<Provider>(); //Création d'une liste de provider
     
                //Gestion des providers - Création de deux faux providers manuellement
                Provider prov1 = new Provider("AWAKE 15000 Test1\r\n");
                providerList.Add(prov1);
                Provider prov2 = new Provider("AWAKE 15000 Test2\r\n");
                providerList.Add(prov2);
     
                //Gestion de la communication avec un client
                ClientApp threadHandle = new ClientApp(DEFAULT_PORT);
                Thread th = new Thread(new ThreadStart(threadHandle.clientCom));
                th.Start();
     
                //Appuyer sur une touche pour fermer la console
                Console.ReadKey();
            }
    Dans mon thread ClientAPP j'ai ce bout de code qui fonctionne parfaitement :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    private string listrResponse()
            {
                string response = "RLIST Test1,INTEGER Test2,INTEGER\r\n";
                return response;
            }
    Seulement j'aimerais plutôt faire un truc comme ceci :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    private string listrResponse()
            {
                string response = "RLIST";
                foreach (Provider prov in providerList)
                {
                    response += " " + prov.ressource + "," + prov.type;
                }
                response += "\r\n";
                return response;
            }
    Mais j'obtiens 'The name doesn't exist in the current context'.
    Si je met smartHub.providerList (mon main est dans smarthub) j'obtiens 'SmartHub does not containt a definition for 'providerlist'.

    J'ai tenté de mettre un 'public' devant ma liste mais ça ne change rien...

    Ma question : est-il donc possible de 'partager' une liste entre thread et si oui, c'est quoi l'astuce ?

    En vous remerciant

    NB : Provider étant une classe :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    class Provider
        {
            public string ressource;
            public string port;
            public string type;
     
            public Provider(string awake)
            {
                ressource = awake.Substring(awake.LastIndexOf(" ")+1, awake.IndexOf("\r\n") - awake.LastIndexOf(" ")-1);
                port = awake.Substring(awake.IndexOf(" ") + 1, awake.LastIndexOf(" ") - awake.IndexOf(" ")-1);
                type = "INTEGER";
            }
        }

  2. #2
    Expert confirmé
    Avatar de popo
    Homme Profil pro
    Analyste programmeur Delphi / C#
    Inscrit en
    Mars 2005
    Messages
    2 667
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Analyste programmeur Delphi / C#
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Mars 2005
    Messages : 2 667
    Points : 5 235
    Points
    5 235
    Par défaut
    providerList est une variable local à la méthode main. Il est impossible d'y accéder à partir d'une autre méthode ou un sein d'un Objet quelconque.

    Il faut un objet partagé.
    Tu pourrait la déclarer comme propriété de ta classe mais ce n'est pas une bonne pratique selon moi.

    Le mieux est d'avoir un objet dédié à cela.
    Cet objet devra gérer la lecture et l'écriture de manière à ce que deux thread puisse taper dedans sans accès concurrent.
    La manière dont tu as pensé ton code m'indique que tu n'es pas familier des thread (ou qu'il y a quelque subtilités qui t'ont échappé)

    La lecture de ces pages devrait t'éclairer et te donner différentes pistes :
    http://emerica.developpez.com/csharp/threads/#LB
    https://msdn.microsoft.com/fr-fr/lib...(v=vs.71).aspx
    http://tahe.developpez.com/dotnet/csharp/?page=page_11
    http://stackoverflow.com/questions/6...etween-threads

  3. #3
    Candidat au Club
    Femme Profil pro
    Enseignant
    Inscrit en
    Mars 2017
    Messages
    4
    Détails du profil
    Informations personnelles :
    Sexe : Femme
    Localisation : Belgique

    Informations professionnelles :
    Activité : Enseignant
    Secteur : Enseignement

    Informations forums :
    Inscription : Mars 2017
    Messages : 4
    Points : 2
    Points
    2
    Par défaut
    Bonjour,

    Merci pour cette réponse, je vais lire tout cela et voir comment je peux faire.

    Sinon pour ce qui est des thread, l'idée est d'en avoir un par 'fonction' du programme, soit :
    • communication avec un client (éventuellement plusieurs à terme)
      - Le client demande la liste des providers dispo (le program lui envoit)
      - Le client fait une demande query sur un provider (le program envoit la réponse après avoir interrogé le provider)
    • réception des message AWAKE des providers
      - Construction de la liste des providers selon ceux qui se sont annoncés
    • communication avec un provider
      - Envoie d'une requête (en provenance d'un client), réception de la valeur (renvoit au client qui l'a demandé)



    Je vais donc lire tout cela et voir si je démarre bien

  4. #4
    Candidat au Club
    Femme Profil pro
    Enseignant
    Inscrit en
    Mars 2017
    Messages
    4
    Détails du profil
    Informations personnelles :
    Sexe : Femme
    Localisation : Belgique

    Informations professionnelles :
    Activité : Enseignant
    Secteur : Enseignement

    Informations forums :
    Inscription : Mars 2017
    Messages : 4
    Points : 2
    Points
    2
    Par défaut
    Rebonjour,

    Je crois donc entrevoir la façon de procéder (ou alors j'ai rien compris ).

    J'ai donc repris mon code, créé un objet pour ma liste :

    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
    class ProviderList
        {
            public List<Provider> providerList; //Création d'une liste de provider
     
            public ProviderList()
            {
                providerList = new List<Provider>();
            }
            //Ajout d'un provider dans la liste selon message AWAKE reçu
            public void Add(string awake)
            {
                providerList.Add(new Provider(awake));
            }
     
            //Envoit de la liste des providers pour génération du message RLIST
            public string List()
            {
                string response = "";
                foreach (Provider prov in providerList)
                {
                    response += " " + prov.ressource + "," + prov.type;
                }
                return response;
            }
        }
    et deux Threads (un pour la gestion de la liste et l'autre pour le client qui doit la lire), ce qui donne 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
    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
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    class SmartHub
        {
            public const int DEFAULT_PORT = 15250;                      //Port utilisé par le client
            public static ProviderList provList = new ProviderList();   //Création d'une liste de providers
     
            //Creation du smarthub selon le port
            static void Main(string[] args)
            {
     
                //Gestion des providers
                Thread thProviderList = new Thread(new ThreadStart(ProviderList));
                thProviderList.Start();
     
                //Gestion de la communication avec un client
                Thread thClientCom = new Thread(new ThreadStart(ClientCom));
                thClientCom.Start();
     
                //Appuyer sur une touche à la fin pour fermer la console
                Console.ReadKey();
            }
     
            public static void ProviderList()
            {
                //Création de deux fake providers
                //Temporaire, devra recevoir les AWAKE en provenance des providers
                provList.Add("AWAKE 15000 Test1\r\n");
                provList.Add("AWAKE 15000 Test2\r\n");
     
            }
            public static void ClientCom()
            {
                bool stop = false;
                bool isStarted = false;
                bool isConnected = false;
                string buffer = null; //Buffer pour communication avec client
     
                TcpListener ecoute = null;
                TcpClient client = null;
                try
                {
                    ecoute = new TcpListener(IPAddress.Any, DEFAULT_PORT);
                    ecoute.Start();
                    isStarted = true;
                    client = ecoute.AcceptTcpClient();
                    isConnected = true;
                    StreamReader fromClient = new StreamReader(client.GetStream(), Encoding.UTF8);
                    StreamWriter toClient = new StreamWriter(client.GetStream(), Encoding.UTF8);
     
                    while (!stop)
                    {
     
                        string ligne = fromClient.ReadLine();
     
                        switch (ligne.Substring(0, 1))
                        {
                            case "L":
                                Regex RegexL = new Regex(@"^LISTR$");
                                if (RegexL.IsMatch(ligne))
                                {
                                    //Réception de la commande LISTR
                                    Console.WriteLine("CMD IN - " + ligne);
                                    //Génération de la réponse au LISTR du client
                                    buffer = "RLIST" + provList.List() + "\r\n";
                                    toClient.Write(buffer);
                                    toClient.Flush();
                                    //Affichage que la réponse a été envoyée
                                    Console.WriteLine("CMD OUT - " + buffer);
                                }
                                else
                                    Console.WriteLine("CMD IN - L ERROR");
                                break;
                            case "Q":
                                Regex RegexQ = new Regex(@"^QUERY [A-Za-z0-9]{1,50}$");
                                if (RegexQ.IsMatch(ligne))
                                {
                                    //Réception d'une commande Query
                                    Console.WriteLine("CMD IN - " + ligne);
                                    //Génération de la réponse au Query du client
                                    buffer = queryResponse(ligne.Substring(6));
                                    toClient.Write(buffer);
                                    toClient.Flush();
                                    //Affichage que la réponse a été envoyée
                                    Console.WriteLine("CMD OUT - " + buffer);
                                }
                                else
                                    Console.WriteLine("CMD IN - Q ERROR");
                                break;
                            case "S":
                                Regex RegexS = new Regex(@"^SAYONARA$");
                                if (RegexS.IsMatch(ligne))
                                {
                                    //Réception d'une commande de déconnexion
                                    Console.WriteLine("CMD IN - " + ligne);
                                    //Fermeture de la communication client
                                    client.Close();
                                    isConnected = false;
                                    ecoute.Stop();
                                    isStarted = false;
                                    stop = true;
                                }
                                else
                                    Console.WriteLine("CMD IN - S ERROR");
                                break;
                            default:
                                //Affichage de la réception d'une commande inconnue du client
                                Console.WriteLine("CMD IN - ERREUR CMD INCONNUE");
                                break;
                        }
                    }
     
                }
                catch (SocketException exception)
                {
                    Console.WriteLine(exception.StackTrace);
                }
                finally
                {
                    if (isConnected) client.Close();
                    if (isStarted) ecoute.Stop();
     
                }
            }
     
            //Génération de la réponse au Query du client
            //Temporaire - Query sera envoyé au provider qui fournira réponse
            private static string queryResponse(string id_ressource)
            {
                string response = null;
                if (id_ressource == "Test1")
                    response = "VALUE " + id_ressource + " 10\r\n";
                else if (id_ressource == "Test2")
                    response = "VALUE " + id_ressource + " 20\r\n";
                else
                    response = "ERROR\r\n";
                return response;
            }
        }
    Ca fonctionne très bien puisque le thread de gestion de la liste à amplement le temps de faire son boulot (créer deux providers) avant que je ne démarre le client, dont la communication a lieu sans problème.

    Mais bon à terme, je recevrais des 'AWAKE' toutes les trentes secondes et ce thread tournera pour ainsi dire en boucle infinie, il serait donc opportun que mon client n'aille pas 'lire' la liste alors que je suis en train d'écrire dedans... je supposes donc que je dois utiliser un lock(), mais j'ai du mal à définir l'endroit où je doit le mettre considérant qu'un thread utilise la méthode pour écrire dans la liste et que l'autre utilise une méthode pour le lire seulement... Bref, je dois encore approfondir cette partie du problème... demain

    Et bien sûr je devrais modifier mon objet pour ne pas ajouter un provider déjà existant si ce dernier s'annonce toutes les 30 secondes, mais ça c'est pas vraiment un problème.

  5. #5
    Candidat au Club
    Femme Profil pro
    Enseignant
    Inscrit en
    Mars 2017
    Messages
    4
    Détails du profil
    Informations personnelles :
    Sexe : Femme
    Localisation : Belgique

    Informations professionnelles :
    Activité : Enseignant
    Secteur : Enseignement

    Informations forums :
    Inscription : Mars 2017
    Messages : 4
    Points : 2
    Points
    2
    Par défaut
    Bonjour de nouveau,

    Je crois avoir trouvé mon bonheur

    J'ai donc créé un objet "private static Object _lockProvList = new object();"

    Et dans mes Thread, lorsque je travaille sur mon provList , je lock les lignes :
    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
    public static void ProviderList()
            {
                //Création de deux fake providers
                //Temporaire, devra recevoir les AWAKE en provenance des providers
                lock (_lockProvList)
                {
                    provList.Add("AWAKE 15000 Test1\r\n");
                    provList.Add("AWAKE 15000 Test2\r\n");
                    Console.WriteLine("Début attente");
                    Thread.Sleep(10000); //Temps d'attente pour test
                    Console.WriteLine("Fin attente");
                }
            }
     
             public static void ClientCom()
            {
                  ...            
                   Console.WriteLine("CMD IN - " + ligne);
                   //Génération de la réponse au LISTR du client
                   lock (_lockProvList)
                   {
                         buffer = "RLIST" + provList.List() + "\r\n";
                   }                                
                   toClient.Write(buffer);
                   toClient.Flush();
                   //Affichage que la réponse a été envoyée
                   Console.WriteLine("CMD OUT - " + buffer); 
                 ...
             }
    Pour tester j'ai démarrer le client, puis ensuite mon programme...
    Cela affiche bien "Début d'attente" du premier Thread puis "CMD IN - LIST" qui indique que j'ai reçu la demande du client de recevoir la liste des providers et que je dois lui fournir réponse.
    10 secondes se passe (le Thread.sleep de l'écriture sur le provList)
    J'affiche "Fin attente" puis "CMD OUT - ..."
    Ce qui tend à confirmer que mon thread ClientCom ne parvient pas à lire ma liste tant que l'autre Thread n'a pas fini d'écrire dedans !

    Merci donc pour ces pistes qui m'ont permis d'y voir plus clair

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. [MySQL] Requête afficher une liste d'information comprise entre deux dates
    Par karamaster dans le forum PHP & Base de données
    Réponses: 17
    Dernier message: 17/08/2015, 20h20
  2. Réponses: 0
    Dernier message: 03/06/2015, 09h08
  3. [CR XI] Partage d'une liste de valeurs entre état et sous-état
    Par EXPE43 dans le forum SAP Crystal Reports
    Réponses: 1
    Dernier message: 30/12/2014, 13h01
  4. Partage d'une liste chainée entre Processus
    Par la_chevre dans le forum Débuter
    Réponses: 7
    Dernier message: 09/10/2008, 12h35
  5. Cherche à créer une liste de choix d'entrée
    Par vally74 dans le forum Macros et VBA Excel
    Réponses: 1
    Dernier message: 15/05/2008, 11h38

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