[ADA] Multitâche, exclusivité d'accès à une variable

Multitâche, exclusivité d'accès à une variable [ADA] - Ada - Programmation

Marsh Posté le 03-02-2003 à 18:27:28    

Voila un bout de code qui est censé garantir l'exclusivité d'accès en écriture à une variable mais j'ai du mal à expliquer comment :
 

Code :
  1. task VAR_PROTEGEE is
  2.     entryLIRE(X:out ITEM);
  3.     entryECRIRE(X:in ITEM);
  4. end;
  5. task body VAR_PROTEGEE is
  6.     V:INTEM;
  7. begin
  8.     accept ECRIRE(X:in ITEM) do
  9.             V:=X;
  10.     end;   
  11.     loop
  12.         select
  13.             accept LIRE(X:out ITEM) do
  14.                 X:=V;
  15.             end
  16.         or
  17.             accept ECRIRE(X:in ITEM) do
  18.                 V:=X;
  19.             end
  20.         end select;
  21.     end loop;
  22. end VAR_PROTEGEE;


 
L'explication est elle que tant qu'on est en lecture(LIRE) de la variable V, la tâche ECRIRE étant située également dans le bloc (loop ... end loop) la variable V est protégée en écriture ?
     

Reply

Marsh Posté le 03-02-2003 à 18:27:28   

Reply

Marsh Posté le 04-02-2003 à 16:38:43    

Pschitt a écrit :

Voila un bout de code qui est censé garantir l'exclusivité d'accès en écriture à une variable mais j'ai du mal à expliquer comment :
 

Code :
  1. task VAR_PROTEGEE is
  2.     entryLIRE(X:out ITEM);
  3.     entryECRIRE(X:in ITEM);
  4. end;
  5. task body VAR_PROTEGEE is
  6.     V:INTEM;
  7. begin
  8.     accept ECRIRE(X:in ITEM) do
  9.             V:=X;
  10.     end;   
  11.     loop
  12.         select
  13.             accept LIRE(X:out ITEM) do
  14.                 X:=V;
  15.             end
  16.         or
  17.             accept ECRIRE(X:in ITEM) do
  18.                 V:=X;
  19.             end
  20.         end select;
  21.     end loop;
  22. end VAR_PROTEGEE;


 
L'explication est elle que tant qu'on est en lecture(LIRE) de la variable V, la tâche ECRIRE étant située également dans le bloc (loop ... end loop) la variable V est protégée en écriture ?
       


 
c'est le select ...end select qui exclut que 2 entrées soient activent en même temps, ce qui veut dire dans ton cas que les lectures sont exclusives entre elles, les écritures sont exclusives entre elles et les lectures sont exclusives par rapport aux écritures et les écritures sont exclusives par rapport aux lectures.
 
En gros un seul point d'exécution au plus a le droit de se trouver dans un select.
 
Il existe une solution plus fine à base d'objets protégés, qui t'auraient permis d'avoir des lecture concurrentes et des écritures exclusives.

Reply

Marsh Posté le 04-02-2003 à 16:50:33    

Exactement. Si mes connaissances Ada ne sont pas trop rouillées, ça devrait donner (attention, Ada 95 only):
 

Code :
  1. protected type Var_Protegee is
  2.     function Read return Item;
  3.     procedure Write (a_Value : in Item);
  4.   private
  5.     V : Item;
  6.   end Var_Protegee;
  7.   protected body Var_Protegee is
  8.     function Read return Item is
  9.     begin
  10.       return V;
  11.     end Read;
  12.     procedure Write (a_Value : in Item) is
  13.     begin
  14.       V := a_Value;
  15.     end Write;
  16.   end Var_Protegee;


Message édité par dsls le 04-02-2003 à 16:52:06
Reply

Marsh Posté le 04-02-2003 à 22:21:52    

Dsls a écrit :

Exactement. Si mes connaissances Ada ne sont pas trop rouillées, ça devrait donner (attention, Ada 95 only):
 

Code :
  1. protected type Var_Protegee is
  2.     function Read return Item;
  3.     procedure Write (a_Value : in Item);
  4.   private
  5.     V : Item;
  6.   end Var_Protegee;
  7.   protected body Var_Protegee is
  8.     function Read return Item is
  9.     begin
  10.       return V;
  11.     end Read;
  12.     procedure Write (a_Value : in Item) is
  13.     begin
  14.       V := a_Value;
  15.     end Write;
  16.   end Var_Protegee;




 
pas testé mais rien à redire. C'est même mieux car tu as une fonction qui retourne un résultat pour la lecture et pas un vieux passage de la valeur de retours par effets de bord => plus clair, plus simple.

Reply

Marsh Posté le 05-02-2003 à 10:04:46    

Vous auriez un lien qui explique les types protégés d'Ada sur le Web ? A part le bon vieux LRM, je n'ai rien trouvé sur AdaHome...  :(

Reply

Marsh Posté le 05-02-2003 à 14:28:58    

En fait, je ne situais pas comment, dans le code du type protégé de Pschitt, le compilateur Ada pouvait autoriser les appels concurrents à la fonction et pas à la procédure. Dans le code, tien ne les distingue explicitement (à part le fait que l'une est une fonction et l'autre une procédure).
 
J'ai trouvé ceci cependant pour répondre à ma question :

Citation :

Within a protected body we can have a number of subprograms and the implementation is such that (like a monitor) calls of the subprograms are mutually exclusive and thus cannot interfere with each other. A procedure in the protected body can access the private data in an arbitrary manner whereas a function is only allowed read access to the private data. The implementation is consequently permitted to perform the useful optimization of allowing multiple calls of functions at the same time.


 
Extrait de cette page : http://www.adaic.com/standards/95r [...] 1-2.html#9

Reply

Marsh Posté le 05-02-2003 à 16:02:43    

BifaceMcLeOD a écrit :

En fait, je ne situais pas comment, dans le code du type protégé de Pschitt, le compilateur Ada pouvait autoriser les appels concurrents à la fonction et pas à la procédure. Dans le code, tien ne les distingue explicitement (à part le fait que l'une est une fonction et l'autre une procédure).
 
J'ai trouvé ceci cependant pour répondre à ma question :

Citation :

Within a protected body we can have a number of subprograms and the implementation is such that (like a monitor) calls of the subprograms are mutually exclusive and thus cannot interfere with each other. A procedure in the protected body can access the private data in an arbitrary manner whereas a function is only allowed read access to the private data. The implementation is consequently permitted to perform the useful optimization of allowing multiple calls of functions at the same time.


 
Extrait de cette page : http://www.adaic.com/standards/95r [...] 1-2.html#9


 
C'est la différence classique fonction/procédure :
une fonction est un machin à qui on applique des arguments (0 ou plus arguments) et dont on attend un résultat. Dans certains langages, la machin en question n'a même pas de droit de faire un effet de bord (affectation de variable par exemple), c'est pas fait pour.
Un procédure est une instruction qui une fois exécutée a modifié l'état de l'environement (en changeant la valeur d'une variable, en poussant dans un stream).
 
Evidement, la plupart des langages mélangent allègrement tout et les déceloppeurs n'ayant jamais eu cette notion clairement enseignée mélangent (par ex. en faisant des procédures avec un paramètre out au lieu d'une fonction sans effet de bords).
 
D'où la logique du comportement des objets protégés :
les fonction mattent mais ne touchent pas : elles peuvent matter à plusieurs.
les procédures touchent : problème de concurrence -> exclusivité.
 
Les entries sont en fait des procédures qui peuvent être gardées : la garde est une expression booléenne qui, si elle est fausse au moment de l'appel de l'entry bloquera l'appellant jusqu'à ce qu'elle devienne vraie, sans bloquer les appels de fonction sur l'objet. Si tu avais fait un "wait" en début de procédure, tu aurais perdu la possibilité d'envoyer des appels de fonction sur l'objet pendant l'attente -> ça tient pas la charge.

Reply

Marsh Posté le 05-02-2003 à 23:18:30    

Mais du coup tu ne peux pas faire de fonction du genre :

function Func returns TheValueType is
begin
   if not-initialised then
      initialise();   -- Appel d'une procédure qui initialise l'objet.
   end if;
 
   return theValue;
end Func;


puisque du coup, il y a effet de bord.
 
Si c'est le cas, je suppose que tu vas me répondre, l'utilisateur n'a qu'à appeler explicitement la procédure d'initialisation, quitte à ensuite lever une exception dans la fonction si tout n'est pas convenablement initialisé...

Reply

Marsh Posté le 05-02-2003 à 23:42:14    

Citation :


Si c'est le cas, je suppose que tu vas me répondre, l'utilisateur n'a qu'à appeler explicitement la procédure d'initialisation, quitte à ensuite lever une exception dans la fonction si tout n'est pas convenablement initialisé...


C'est ça. Dans ton cas bien précis, tu peux faire une procédure avec ta valeur en out, ce qui remplace la fonction et laisse plus transparaître les effets de bord de l'appel. Ou mieux, tu encapsules ton type protégé dans une variable contrôlée, comme ça plus besoin d'appel explicite à Initialize(). Bon par contre coupler type protégé+type contrôlé amène parfois à certaines siouxeries pas évidentes (principalement à cause des types contrôlés d'ailleurs) ... Mais bon, n'est pas fortement typé qui veut :D


Message édité par dsls le 05-02-2003 à 23:43:01
Reply

Marsh Posté le 06-02-2003 à 14:03:45    

Du genre ? :??:

Reply

Marsh Posté le 06-02-2003 à 14:03:45   

Reply

Marsh Posté le 07-02-2003 à 03:18:43    

BifaceMcLeOD a écrit :

Mais du coup tu ne peux pas faire de fonction du genre :

function Func returns TheValueType is
begin
   if not-initialised then
      initialise();   -- Appel d'une procédure qui initialise l'objet.
   end if;
 
   return theValue;
end Func;


puisque du coup, il y a effet de bord.
 
Si c'est le cas, je suppose que tu vas me répondre, l'utilisateur n'a qu'à appeler explicitement la procédure d'initialisation, quitte à ensuite lever une exception dans la fonction si tout n'est pas convenablement initialisé...


 
Je ne pense pas que l'utilisateur a à se préocuper de ce genre de détails. Soit la valeur d'initialisation doit être fournie par l'utilisateur et tu te fondes sur une sorte de "construction" avec le discriminant par ex. (piqué du lien plus haut) :  

protected type Counting_Semaphore(Start_Count: Integer := 1) is
      entry Secure;
      procedure Release;
      function Count return Integer;
   private
      Current_Count: Integer := Start_Count;
   end Counting_Semaphore;


 
Ou alors la valeur par défaut est intrinsèque et donc tu peux la coder en dur :

protected type Counting_Semaphore is
      entry Secure;
      procedure Release;
      function Count return Integer;
   private
      Current_Count: Integer := 0;
   end Counting_Semaphore;


 
 
 
Je fait part d'une réflection qui m'est venue à l'esprit en cherchant de tête à répondre à ta question (car en réalité on est pas exactement dans le même modèle, ton initialisation est "lazy", fainéante donc à la demande, si elle est coûteuse et a une probabilité importante d'être inutile, c'est un choix. Mon initialisation est "eager", motivée et donc systématiquement exécutée à l'instanciation du type).
 
Donc je me disait, il suffit d'appeler la procédure d'initialisation de l'objet dans le if : appeller une procédure de type protégé est exclusif, comme on est dans le if, l'exclusivité n'a lieu qu'une fois et tout va bien. Sauf qu'il y a un problème de synchronisation :
2 threads rentrent dans la fonction , rentrent dans le if (c'est les 2 premières) et chacun attend que l'autre se barre de la fonction pour exécuter l'initialisation -> ça peut durer longtemps.
Il doit y avoir moyen de faire plus intelligent, peut-être à base d'entries gardées, mais j'ai pas d'idées.


Message édité par nraynaud le 07-02-2003 à 03:30:44
Reply

Sujets relatifs:

Leave a Replay

Make sure you enter the(*)required information where indicate.HTML code is not allowed