• Aucun résultat trouvé

Déclaration de variables et gestion de l'aléatoire

4.2 Syntaxe et sémantique du langage

4.2.9 Déclaration de variables et gestion de l'aléatoire

La gestion du hasard se fait à l'aide de variables aléatoires. Ces variables sont

initial-isées à l'aide de fonctions aléatoires de bibliothèques extérieures ou de fonctions aléatoires

prédénies. Elles sont ensuite utilisées dans les gardes des règles. Il existe deux façons de

déclarer et d'initialiser les variables (aléatoires ou non) :

Daemon test

{ // Ici nb_g1 est initialise avec la valeur 500

int nb_g1 = FAIL_SIZE (G1) ; }

Group G1

{ size = 500 ;

daemon = test ; }

Fig. 4.25 La taille d'un tableau de machines.

déclaration globale dans un automate :

Lorsqu'une variable est déclarée globalement dans un automate, elle est initialisée

lors du lancement de l'automate. Cette variable est visible et utilisable par tous

les noeuds de l'automate. La déclaration et l'utilisation de variable globale se fait

comme dans l'exemple de la gure 4.26

Daemon Mesto

{ int wait_msg = 0 ;

node 1 :

?msg && wait_msg==25 -> wait_msg = 0 ; goto 2 ;

?msg && wait_msg<>25 -> wait_msg = wait_msg + 1 ;

node 2 :

?msg -> !kill_random, goto 1 ; }

Fig. 4.26 Les variables globales.

Dans cet exemple, l'automate nommé Mesto attend 25 messages msg et diuse le

message kill_random lorsqu'il reçoit de nouveau le message msg (donc au 26ième

message msg) et il recommence cette procédure indéniment.

déclaration locale dans un automate :

Lorsqu'une variable est déclarée localement dans un automate, elle est initialisée

quand l'automate se positionne pour la première fois dans ce noeud et qu'il passe

d'un autre noeud à ce noeud (en fait, les variables locales ne sont pas réinitialisées

lors de récursion sur un même noeud). Ces variables ne sont visibles que dans le

noeud où elles sont déclarées. La déclaration et l'utilisation de variables locales se

font comme dans l'exemple de la gure 4.27.

Daemon Mesto

{ node 1 :

int wait_msg = 0 ;

?msg && wait_msg==25 -> goto 2 ;

?msg && wait_msg<>25 -> wait_msg = wait_msg + 1 ;

node 2 :

?msg -> !kill_random, goto 1 ; }

Fig. 4.27 Les variables locales.

en utilisant des variables locales.

Remarque 2 : lorsque les noeuds ne sont pas spéciés, toutes les variables sont des

variables globales comme dans l'exemple de la gure 4.28.

Daemon Mesto

{ int wait_msg = 0 ;

?msg && wait_msg<>26 -> wait_msg = wait_msg + 1 ;

?msg && wait_msg==26 -> !kill_random, wait_msg = 0 ; }

Fig. 4.28 Les variables dans un automate sans n÷uds.

Cet exemple correspond au même exemple que précédemment mais en n'utilisant

pas de noeuds dans l'automate.

déclaration et utilisation d'une variable aléatoire :

l'utilisateur peut utiliser dans ses actions, ou pour initialiser une variable, le résultat

de la fonction prédénie FAIL_RANDOM(min, max) qui renvoie un entier aléatoire

uniforme compris dans [min, max]. Il peut aussi fournir d'autres fonctions dont il

peut vouloir se servir via une bibliothèque dynamique. La gure 4.29 présente un

exemple d'utilisation d'une variable aléatoire.

Daemon random_halt

{ int rand = FAIL_RANDOM(0,10) ;

?fail_or_not && rand == 4 -> halt ; }

Fig. 4.29 Les variables aléatoires.

A la réception d'un message fail_or_not , l'automate random_halt fait

crasher le programme testé suivant la valeur de la variable aléatoire rand .

Remarque : on ne peut pas faire appel à une fonction dans une garde. Il faut

initialiser une variable avec cette fonction puis l'utiliser dans la garde. Cette mesure

est prise pour éviter certains problèmes sémantiques liés à l'implantation.

Utilisation de bibliothèques dynamiques

L'utilisateur peut vouloir utiliser des fonctions d'une bibliothèque dynamique. Par

exemple pour calculer une variable aléatoire en utilisant une fonction aléatoire d'une

bibliothèque dynamique. Pour cela il doit donner la signature de cette fonction ainsi que

le nom de la bibliothèque où elle se trouve comme dans l'exemple de la gure 4.30.

/* declaration d'une fonction nommee "mon_hazard" prennant en entree

deux entiers et retournant un entier. Cette fonction fait partie

de la bibliotheque "libutils.so" */

function int mon_hasard(int, int) in library "libutils.so" ;

/* si a la reception de "fail_or_not", mon_hasard(3, 400) renvoi 4,

alors arret denitif de l'application testee. */

Daemon Adv1

{ int rand = mon_hasard(3, 400) ;

?fail_or_not && rand == 4 -> halt ; }

Fig. 4.30 Les bibliothèques dynamiques.

Utilisation de la commande always

La commande always permet de forcer l'initialisation d'une variable pendant la

récur-sion sur un même noeud (après une suite d'actions) comme le montre la gure 4.31.

Dans cet exemple, au bout de x secondes (x étant une variable aléatoire uniforme

com-prise entre 10 et 20), l'automate coucou diuse le message faire_1 ou faire_2

selon la valeur de la variable aléatoire rand (la valeur de cette variable étant obtenue

grâce à la fonction mon_hasard de la bibliothèque externe libutils.so). Une fois le

mes-sage envoyé, la valeur du minuteur est recalculée et le minuteur est réarmé.

function int mon_hasard(int, int) in library "libutils.so" ;

Daemon coucou

{ // le temps global est en millisecondes

always time_g timer = FAIL_RANDOM(10,20) ;

always rand = mon_hazard(3, 400) ;

timer && rand >= 100 -> !faire_1 ;

timer && rand < 100 -> !faire_2 ; }

Fig. 4.31 Utilisation de la commande always.

Initialisations gardées

Il est possible de dénir une règle gardée comme faisant partie de l'initialisation. La

syntaxe pour la dénition de telles règles est présentée dans l'exemple de la gure 4.32.

Daemon toto

{ int rand = FAIL_RANDOM(1,10) ;

// Denition d'une regle gardee initiale :

init rand == 4 -> halt ; }

Fig. 4.32 Les initialisations gardées.

Dans cet exemple, à son initialisation, l'automate tire un nombre aléatoirement et

crashe ou non suivant la valeur de ce nombre.

Remarque 1 : ce type de règle ne sera testé que lors de l'initialisation.

Remarque 2 IMPORTANTE : les restrictions sur les entités des gardes pour ce type de

règle (règle initiale) sont diérentes des restrictions pour les règles standards (voir la

section 4.2.11 introduisant les restrictions sur les gardes).