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

Ada Discussion :

partage de variable sans attente.


Sujet :

Ada

  1. #1
    Invité
    Invité(e)
    Par défaut partage de variable sans attente.
    Bonjour,
    Je souhaite partager entre plusieurs taches une variable qui est modifiée par une de ces taches sans qu'une de ces taches soit pénalisé par l'attente.

    Description :

    J'ai d'abord une tache Rackctrl dans mon paquetage Main qui interface la console.
    Dans cette console, je souhaite, pouvoir entrée un caractère pour démarrer ou arrêter la tacche qui modifie la variable,ou arrêter la tache à tout moment, et surtout afficher la variable modifier par une l'tache.
    Typiquement Rackctrl :
    Code ada : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
     
    package Racklog.Main is
     
       task Rackctrl is
          entry Initialize;
          entry Receive(Char : in Character);
          entry Halt;
       end Rackctrl;   
     
    end Racklog.Main;

    Code ada : 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
     
    package body Racklog.Main is
     
       task body Rackctrl is
          End_Of_Task : Boolean := True;
       begin
     
          accept Initialize do
    	 End_Of_Task := False;
          end Initialize;
     
          while not End_Of_Task loop	 	          
    	 -- ici, je dois afficher la variable.
             -- Si la tache qui modifie la variable est démarrée, je doit attendre la nouvelle valeur.
             -- si non, j'attends pas.
    	 select
     
    	    accept Receive(Char : in Character);
     
    	 or
     
    	    accept Halt do
    	       End_Of_Task := True;
    	    end Halt;
    	    exit;	    	 	    	    
    	 end select;
          end loop;
       end Rackctrl;   
     
    end Racklog.Main;

    Au lieu des commentaires, j'écrirais bien pour une tache nommé Racksheduler :
    Code ada : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
    Afficher(variable)
    if Running then
       Racksheduler.send(Ma_Variable);
    end if;
    Mais je trouve pas ça très joli perso. N'y a t- il pas plus légé ?

    Merci pour vos réponse.


    edit, j'ai déjà modifier le code proposé en mieux :
    Mais je suis preneur de solution autres !

  2. #2
    Membre averti Avatar de Blackknight
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Février 2009
    Messages
    214
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 50
    Localisation : France, Seine Maritime (Haute Normandie)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Février 2009
    Messages : 214
    Points : 383
    Points
    383
    Par défaut
    Ton code fonctionne parfaitement, pourquoi vouloir le changer ?
    Une alternative serait de regarder du côté des guards décrit ici mais cela n'aurait vraiment d'intérêt que si tu avais du code spécifique lors du passage par End_Of_Task à false.

    Par contre, y a un truc qui me chiffonne. A quoi sert Initialize, une initialisation à false suffisant ? Juste pour avoir un moyen de démarrer ta tâche quand tu le désires ?

  3. #3
    Invité
    Invité(e)
    Par défaut
    Bonjour, merci Blackknight pour ta réponse.

    En fait j'ai même viré le test, et j'ai implémenté une entré dans la section de suspend de traitement dans Racksheduler. ce qui fait que ça retourne jour la valeur courante de la variable, stopé ou en cours de traitement.

    Dans initialise j'initialise un type après la saisie d'unparamètre par l'utilisateur, si le paramètre n'est pas entrée (fin de texte) je retourne True pour End_of_task.
    Les exception c'est la misère dans les taches.

  4. #4
    Invité
    Invité(e)
    Par défaut partage de variable avec plusieurs taches.
    bonjour, je reviens avec mon problème etendue par la multiplicité de mes tache "cliente".

    J'avais fait ceci :

    Tache cliente
    Code ada : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
     
    task body Client is
       index : positive := ;
    begin
       loop
           serveur.send(index);
           --opération avec l'index
       end loop;
    end Client;

    Tache cliente
    Code ada : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
     
    task body Serveur is
       index : positive := 1;
    begin
       loop
           accept Send(index : out positive) do
                index := Serveur.index;
           end Send;
           --opération avec l'index
       end loop;
    end Serveur;


    Maintenant, je cherche comment partager l'index avec plusieurs autre tache Cliente.

    J'ai exactement 5 taches (Global, Fx, Lead, Bass, Drums) qui doivent connaitre l'index à tout moment, mais en garantissant que la lecture ne s'effectuera qu'une seule fois pour chacune des tache cliente.

    En espérant être clair, si non je complèterait, s'il vous plait, merci.

    edit du coup c'est partage avec attente.
    Dernière modification par Invité ; 28/10/2012 à 20h21.

  5. #5
    Invité
    Invité(e)
    Par défaut J'ai une idée.
    J'ai eu une idée c'est pas terrible à mon avis mais ça fonctionne.
    J'ai fait une entrée par type de taches, et je gère l'accept avec un tableau de boolean.
    Code ada : 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
     
    task body Serveur is
       Inst_List : array (Quatuor_Type) of Boolean := (others => False);
    begin
       loop
           select
                  when not Inst_List(Global) =>
                      accept Global_Index(Index : out Step_Index_Type) do
                         Index := Step_Index;
                         Inst_List(Global) := True;
                      end Global_Index;
                or
                   when not Inst_List(Fx) =>
                      accept Fx_Index(Index : out Step_Index_Type)  do
                         Index := Step_Index;
                         Inst_List(Fx) := True;
                      end Fx_Index;
                or
                   when not Inst_List(Lead) =>
                      accept Lead_Index(Index : out Step_Index_Type) do
                         Index := Step_Index;
                         Inst_List(Lead) := True;
                      end Lead_Index;
                or
                   when not Inst_List(Bass) =>
                      accept Bass_Index(Index : out Step_Index_Type) do
                         Index := Step_Index;
                         Inst_List(Bass) := True;
                      end Bass_Index;
                or
                   when not Inst_List(Drums) =>
                      accept Drums_Index(Index : out Step_Index_Type) do
                         Index := Step_Index;
                         Inst_List(Drums) := True;
                      end Drums_Index;
                 or delay until date;
                  if Step_Index + 1 > Step_Index_Type'Last then
                      Step_Index := 1;            
                   else
                      Step_Index := Step_Index + 1;
                   end if;
                   Inst_List := (others => False);
            end select;
       end loop;
    end Serveur;

  6. #6
    Membre du Club
    Homme Profil pro
    Enseignant
    Inscrit en
    Avril 2012
    Messages
    29
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Enseignant
    Secteur : Enseignement

    Informations forums :
    Inscription : Avril 2012
    Messages : 29
    Points : 49
    Points
    49
    Par défaut
    Euh ... j'ai un peu survolé le post, alors n'hésite pas à me dire si ça ne répond pas à ta question. Si j'ai bien compris tu as des données partagées entre plusieurs tâches concurrentes ? Alors pourquoi ne pas encapsuler ces données dans un type protected ? Tu fournis les entrées (avec gardes obligatoires) et méthodes associées et elles se feront tout simplement en mutex. Me trompe-je ?

  7. #7
    Invité
    Invité(e)
    Par défaut
    Merci, bonsoir, tu aurais une description un poil plus détaillé ?
    J'ai tout compris mais quel avantage ?

  8. #8
    Membre du Club
    Homme Profil pro
    Enseignant
    Inscrit en
    Avril 2012
    Messages
    29
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Enseignant
    Secteur : Enseignement

    Informations forums :
    Inscription : Avril 2012
    Messages : 29
    Points : 49
    Points
    49
    Par défaut
    Un type protégé ça donne ça (j'ai pris l'exemple d'un type sémaphore) :

    Spécification :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    PROTECTED TYPE T_Semaphore(val_initiale : natural := 0) IS
       ENTRY P ; 
       PROCEDURE V ; 
    PRIVATE
       compteur : natural := val_initiale ;
    END T_Semaphore ;
    Corps :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    PROTECTED BODY T_Semaphore IS
       ENTRY P WHEN compteur = 0 IS
       BEGIN
          compteur := compteur + 1 ; 
       END P ; 
     
       PROCEDURE V IS
       BEGIN
          compteur := compteur - 1 ; 
       END V ;
    END T_Semaphore ;
    Exemple d'utilisation :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
       Sem : T_Semaphore(1) ;
    BEGIN
       Sem.P ; 
       ...
       Sem.V  ;
       ...
    Si je ne dis pas d'âneries, les primitives P et V se font en exclusion mutuelle. Deux tâches ne pourront exécuter Sem.V en même temps. Ainsi, le code ci-dessus est blocant : l'appel à Sem.P ne peut se faire qu'avec un compteur à 0 et non à 1 => mise en attente tant qu'une autre tâche ne libère pas le compteur avec Sem.V. C'est plus lisible qu'une flopée d'accept. Les tâches ne communiquent pas entre elles directement mais via cette variable protégée (=> asynchrone). Les entrées doivent obligatoirement avoir une garde. Ici, la donnée protégée est ma variable compteur. Mais il peut très bien ne pas y avoir de partie private. Par exemple :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    PROTECTED TYPE T_Ecran IS
       PROCEDURE Affichage ;
    END T_Ecran ;
    Ainsi c'est l'accès au moniteur qui est protégé, l'affichage d'un texte à un endroit précis ne sera pas interrompu par une procédure similaire.

  9. #9
    Invité
    Invité(e)
    Par défaut
    Plus j'y pense, moins j'ai envie d'y penser.

    T'as vue le corps serveur ... Comment je fait pour savoir si une tache particulière est déjà passé ou pas.
    Je sais en gros ce qu'est l'exclusion mutuelle, mais c'est pas le sujet.
    Je sais qu'avec des sémaphore on peut garantir une les opérations dans une section critique. En gros. Mais là je vois pas comment tu peux savoir qui tu a servie ou pas.

  10. #10
    Invité
    Invité(e)
    Par défaut
    Bonjour, je fais un truc qui utilise un sémaphore, je me tape des interblocage.

    Si vous aviez plus ample motivation pour transposer mon code avec l'utilisation des sémaphore je suis preneur.

  11. #11
    Invité
    Invité(e)
    Par défaut
    Bonjour,


    Donc le but était de partager de la donnée entre plusieurs tache.
    En fait il s'agit un compositeur virtuel avec des générateur musicaux qui exploite un séquenceur relier à un périphérique MIDI.

    Le tout était d'ordonnancer le tout, comme souvent.
    Je vous montre ce que j'ai fait vous me direz.

    Voici donc les données à partgaer.
    Code ada : 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
     
    with GNAT.Semaphores;
      use GNAT.Semaphores;
    package Q.Transport is
     
       type Transport_Type is
         record
    	 Tempo          : Tempo_Type      := 120.0;
    	 Signature      : Signature_Type  := (Num_Type'first, Den_Type'first);
    	 Current_Step   : Step_Index_Type := Step_Index_Type'First;
    	 Bar_Index      : Bar_Index_Type  := Bar_Index_Type'First;
    	 Step_Seq       : Step_Seq_Access;
    	 Gate           : Binary_Semaphore(Initially_Available => True,
    					   Ceiling => Default_Ceiling);
          end record;   
       -- Un type qui regroupe les informations sur le transport.
       -- plus un accès à une séquence de pas avec un verrou.
     
       type Transporter_Type is access Transport_Type;
     
       function Quantum(Transporter : in Transporter_Type) return Duration;      
       -- Renvoie la durée d'un pas.
     
    end Q.Transport;

    Le sequenceur
    Code ada : 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
     
    task body Sequencer is
       Date : Time := Clock;
          Transporter : constant Transporter_Type := new Transport_Type;
       Quatuor : array (Quatuor_Type'range) of Boolean := (others => False);
          Done : Boolean := True;
     
    begin
       loop
    	    select
    	       accept Transport(Transporter : out Transporter_Type; Instrument : in Quatuor_type) do
    		  Transporter := Sequencer.Transporter;
    		  Quatuor(Instrument) := True;
    	       end Transport;
    	    or
    	       delay until Date;
     
    	       Done := True;
    	       for I in Quatuor'Range loop
    		  if not Quatuor(I) then
    		     Done := False;
    		    --Text_Io.Put_Line(Quatuor_Type'Image(I));
    		  end if;
    	       end loop;
     
     
    	       if Done then
    		  Quatuor := (others => False);
     
    		  Text_Io.Put_Line("..................... Next !");
    		  Date := Date + Quantum(Transporter);
    		 --or delay 0.01;
    		 --null;
    		 --end select;
    	       else
     
    		  Date := Date + Quantum(Transporter)/10.0;
    	       end if;
     
    	    end select;
    	 end loop;
    end Sequencer;
    Chaque tache qui demande l'information est enregistrée
    Lorsque toute les tache on obtenu l'information on incrémente d'un pas.



    Un générateur.
    Code ada : 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
     
    package body Q.BassDrum_Generator is
     
    task body genrator is
    begin
    Seq.Sequencer.Transport(Transporter, BassDrum);
    loop
     delay until Date + Quantum(Transporter);
     Seq.Sequencer.Transport(Transporter, BassDrum);
     Transporter.Gate.Seize;
    		  if Transporter.Step_Seq /= null then
    			    -- opérations sur le step_seq.	  
    			end if;
    			Transporter.Gate.Release;
       Date := Date + Quantum(Transporter);
     
    end loop;
    On utilise le verrou afin de garantir l'accès au pointeur de la séquence de pas.

    Excusez moi un peu pour l'indentation.
    Dernière modification par Invité ; 26/11/2012 à 22h48.

  12. #12
    Invité
    Invité(e)
    Par défaut
    Bonjour, Alors, le code si dessus, ne me conviens pas finalement.
    D'abord parce qu'il fini par bugger, et d'autres fonctionnalités aussi, comme l'arrêt du programme... ET puis sur windows il marche pas du tout donc, c'est qu'il y a un problème.


    Donc, je me remet à la recherche de solution pour ce programme.
    Vous trouverez les source complète de Quatuor à cette adresse : [URL="http://80.15.188.151/dev[/URL] J'en suis à la version Quatuor-0.2.12.

    Merci pour votre aide.

  13. #13
    Invité
    Invité(e)
    Par défaut variante du séquenceur.
    J'ai tout de même trouvé une variante.

    A comparer avec le code ci-dessus.
    Code ada : 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
     
    task body Sequencer is
       Date : Time := Clock;
          Transporter : constant Transporter_Type := new Transport_Type;
       Quatuor : array (Quatuor_Type'range) of Boolean := (others => False);
          Done : Boolean := True;
     
    begin
       loop
               loop
    	    select
     
    	       accept Transport(Transporter : out Transporter_Type; Instrument : in Quatuor_type) do
    		  Transporter := Sequencer.Transporter;
    		  Quatuor(Instrument) := True;
    	       end Transport;
    	    or
     
     
    	       Done := True;
    	       for I in Quatuor'Range loop
    		  if not Quatuor(I) then
    		     Done := False;
    		    --Text_Io.Put_Line(Quatuor_Type'Image(I));
    		  end if;
    	       end loop;
    	       if Done then
                      exit;
                   end if;
                   end select;
                   end loop;
     
                      delay until Date;
    	          Transporter.Gate.Sieze;
     
                      Text_Io.Put_Line("..................... Next !");
     
                      Transporter.Release;.
     
    		  Quatuor := (others => False);
     
    		  Date := Date + Quantum(Transporter);
     
    	 end loop;
    end Sequencer;


    Ca semble mieux tenir sur Gnu/Linux, mais ça ne marche pas du tout sur Windows.
    Dernière modification par Invité ; 30/11/2012 à 14h23.

Discussions similaires

  1. Permuter deux variables sans variable temporaire
    Par khayyam90 dans le forum Algorithmes et structures de données
    Réponses: 7
    Dernier message: 09/01/2015, 09h02
  2. Partage de variables entre plusieurs pages
    Par bud_gw dans le forum Général JavaScript
    Réponses: 10
    Dernier message: 27/12/2005, 16h42
  3. Sortie standard stockée dans variable sans rc
    Par ggnore dans le forum Linux
    Réponses: 2
    Dernier message: 13/12/2005, 15h46
  4. [PHP-JS] Envoi de variable sans passer par un submit
    Par adilou1981 dans le forum Langage
    Réponses: 4
    Dernier message: 15/11/2004, 20h21
  5. [DLL] partage de variables globales
    Par tut dans le forum MFC
    Réponses: 5
    Dernier message: 29/02/2004, 11h17

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