Publicité
+ Répondre à la discussion
Affichage des résultats 1 à 13 sur 13
  1. #1
    Membre éprouvé
    Homme Profil pro
    Inscrit en
    juin 2006
    Messages
    926
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 44

    Informations forums :
    Inscription : juin 2006
    Messages : 926
    Points : 415
    Points
    415
    Billets dans le blog
    1

    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 :
    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 :
    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 :
    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 éclairé Avatar de Blackknight
    Homme Profil pro Frédéric Praca
    Ingénieur développement logiciels
    Inscrit en
    février 2009
    Messages
    189
    Détails du profil
    Informations personnelles :
    Nom : Homme Frédéric Praca
    Âge : 41
    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 : 189
    Points : 320
    Points
    320

    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
    Membre éprouvé
    Homme Profil pro
    Inscrit en
    juin 2006
    Messages
    926
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 44

    Informations forums :
    Inscription : juin 2006
    Messages : 926
    Points : 415
    Points
    415
    Billets dans le blog
    1

    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
    Membre éprouvé
    Homme Profil pro
    Inscrit en
    juin 2006
    Messages
    926
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 44

    Informations forums :
    Inscription : juin 2006
    Messages : 926
    Points : 415
    Points
    415
    Billets dans le blog
    1

    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 :
    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 :
    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.

  5. #5
    Membre éprouvé
    Homme Profil pro
    Inscrit en
    juin 2006
    Messages
    926
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 44

    Informations forums :
    Inscription : juin 2006
    Messages : 926
    Points : 415
    Points
    415
    Billets dans le blog
    1

    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 :
    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
    Nouveau Membre du Club
    Homme Profil pro
    Enseignant
    Inscrit en
    avril 2012
    Messages
    27
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Enseignant
    Secteur : Enseignement

    Informations forums :
    Inscription : avril 2012
    Messages : 27
    Points : 35
    Points
    35

    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
    Membre éprouvé
    Homme Profil pro
    Inscrit en
    juin 2006
    Messages
    926
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 44

    Informations forums :
    Inscription : juin 2006
    Messages : 926
    Points : 415
    Points
    415
    Billets dans le blog
    1

    Par défaut

    Merci, bonsoir, tu aurais une description un poil plus détaillé ?
    J'ai tout compris mais quel avantage ?

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

    Informations professionnelles :
    Activité : Enseignant
    Secteur : Enseignement

    Informations forums :
    Inscription : avril 2012
    Messages : 27
    Points : 35
    Points
    35

    Par défaut

    Un type protégé ça donne ça (j'ai pris l'exemple d'un type sémaphore) :

    Spécification :

    Code :
    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 :
    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 :
    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 :
    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
    Membre éprouvé
    Homme Profil pro
    Inscrit en
    juin 2006
    Messages
    926
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 44

    Informations forums :
    Inscription : juin 2006
    Messages : 926
    Points : 415
    Points
    415
    Billets dans le blog
    1

    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
    Membre éprouvé
    Homme Profil pro
    Inscrit en
    juin 2006
    Messages
    926
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 44

    Informations forums :
    Inscription : juin 2006
    Messages : 926
    Points : 415
    Points
    415
    Billets dans le blog
    1

    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
    Membre éprouvé
    Homme Profil pro
    Inscrit en
    juin 2006
    Messages
    926
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 44

    Informations forums :
    Inscription : juin 2006
    Messages : 926
    Points : 415
    Points
    415
    Billets dans le blog
    1

    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 :
    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 :
    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 :
    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.

  12. #12
    Membre éprouvé
    Homme Profil pro
    Inscrit en
    juin 2006
    Messages
    926
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 44

    Informations forums :
    Inscription : juin 2006
    Messages : 926
    Points : 415
    Points
    415
    Billets dans le blog
    1

    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
    Membre éprouvé
    Homme Profil pro
    Inscrit en
    juin 2006
    Messages
    926
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 44

    Informations forums :
    Inscription : juin 2006
    Messages : 926
    Points : 415
    Points
    415
    Billets dans le blog
    1

    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 :
    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.

Liens sociaux

Règles de messages

  • Vous ne pouvez pas créer de nouvelles discussions
  • Vous ne pouvez pas envoyer des réponses
  • Vous ne pouvez pas envoyer des pièces jointes
  • Vous ne pouvez pas modifier vos messages
  •