Précédent   Forum du club des développeurs et IT Pro > Autres langages > Autres langages > Ada
Ada Forum d'entraide sur la programmation en langage Ada
Partagez cette discussion sur d'autres réseaux sociaux : Viadeo Twitter Google Facebook Digg Delicious MySpace Yahoo
Réponse
 
Outils de la discussion
Publicité
'
Vieux 19/10/2012, 09h03   #1
jovalise
Membre éclairé
 
Inscription : juin 2006
Messages : 767
Détails du profil
Informations personnelles :
Âge : 43

Informations forums :
Inscription : juin 2006
Messages : 767
Points : 328
Points : 328
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 !
__________________
Mon développement
jovalise est déconnecté   Envoyer un message privé Réponse avec citation 10
Vieux 20/10/2012, 09h43   #2
Blackknight
Membre confirmé
 
Avatar de Blackknight
 
Homme Frédéric Praca
Ingénieur développement logiciels
Inscription : février 2009
Messages : 172
Détails du profil
Informations personnelles :
Nom : Homme Frédéric Praca
Âge : 39
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 : 172
Points : 292
Points : 292
Envoyer un message via AIM à Blackknight Envoyer un message via MSN à Blackknight
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 ?
Blackknight est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 20/10/2012, 20h52   #3
jovalise
Membre éclairé
 
Inscription : juin 2006
Messages : 767
Détails du profil
Informations personnelles :
Âge : 43

Informations forums :
Inscription : juin 2006
Messages : 767
Points : 328
Points : 328
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.
__________________
Mon développement
jovalise est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 28/10/2012, 18h54   #4
jovalise
Membre éclairé
 
Inscription : juin 2006
Messages : 767
Détails du profil
Informations personnelles :
Âge : 43

Informations forums :
Inscription : juin 2006
Messages : 767
Points : 328
Points : 328
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.
__________________
Mon développement
jovalise est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 28/10/2012, 19h37   #5
jovalise
Membre éclairé
 
Inscription : juin 2006
Messages : 767
Détails du profil
Informations personnelles :
Âge : 43

Informations forums :
Inscription : juin 2006
Messages : 767
Points : 328
Points : 328
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;
__________________
Mon développement
jovalise est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 13/11/2012, 00h33   #6
Sigurd9
Nouveau Membre du Club
 
Homme
Enseignant
Inscription : avril 2012
Messages : 26
Détails du profil
Informations personnelles :
Sexe : Homme
Localisation : France

Informations professionnelles :
Activité : Enseignant
Secteur : Enseignement

Informations forums :
Inscription : avril 2012
Messages : 26
Points : 39
Points : 39
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 ?
Sigurd9 est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 13/11/2012, 01h32   #7
jovalise
Membre éclairé
 
Inscription : juin 2006
Messages : 767
Détails du profil
Informations personnelles :
Âge : 43

Informations forums :
Inscription : juin 2006
Messages : 767
Points : 328
Points : 328
Merci, bonsoir, tu aurais une description un poil plus détaillé ?
J'ai tout compris mais quel avantage ?
__________________
Mon développement
jovalise est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 18/11/2012, 12h15   #8
Sigurd9
Nouveau Membre du Club
 
Homme
Enseignant
Inscription : avril 2012
Messages : 26
Détails du profil
Informations personnelles :
Sexe : Homme
Localisation : France

Informations professionnelles :
Activité : Enseignant
Secteur : Enseignement

Informations forums :
Inscription : avril 2012
Messages : 26
Points : 39
Points : 39
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.
Sigurd9 est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 18/11/2012, 20h41   #9
jovalise
Membre éclairé
 
Inscription : juin 2006
Messages : 767
Détails du profil
Informations personnelles :
Âge : 43

Informations forums :
Inscription : juin 2006
Messages : 767
Points : 328
Points : 328
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.
__________________
Mon développement
jovalise est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 25/11/2012, 11h33   #10
jovalise
Membre éclairé
 
Inscription : juin 2006
Messages : 767
Détails du profil
Informations personnelles :
Âge : 43

Informations forums :
Inscription : juin 2006
Messages : 767
Points : 328
Points : 328
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.
__________________
Mon développement
jovalise est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 26/11/2012, 21h11   #11
jovalise
Membre éclairé
 
Inscription : juin 2006
Messages : 767
Détails du profil
Informations personnelles :
Âge : 43

Informations forums :
Inscription : juin 2006
Messages : 767
Points : 328
Points : 328
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.
__________________
Mon développement
jovalise est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 28/11/2012, 23h32   #12
jovalise
Membre éclairé
 
Inscription : juin 2006
Messages : 767
Détails du profil
Informations personnelles :
Âge : 43

Informations forums :
Inscription : juin 2006
Messages : 767
Points : 328
Points : 328
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.
__________________
Mon développement
jovalise est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 29/11/2012, 02h26   #13
jovalise
Membre éclairé
 
Inscription : juin 2006
Messages : 767
Détails du profil
Informations personnelles :
Âge : 43

Informations forums :
Inscription : juin 2006
Messages : 767
Points : 328
Points : 328
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.
__________________
Mon développement
jovalise est déconnecté   Envoyer un message privé Réponse avec citation 00
Réponse
Outils de la discussion

Navigation rapide


Fuseau horaire GMT +2. Il est actuellement 14h44.


 
 
 
 
Partenaires

Hébergement Web