57 5. RETI DI PETRI
In questo capitolo sono presentate le due categorie principali di reti di Petri: le reti di Petri P/T e le reti di Petri colorate o di alto livello. Sono descritti quindi i concetti di base riguardo queste reti necessari per comprendere i motivi della scelta di tale tecnologia e l’uso stesso fatto all’interno di questo lavoro. Dopo è illustrato il tool di sviluppo adottato per creare la rete di petri utilizzata per la creazione dell’automa dei prelievi.
5.1 Reti di Petri P/T 5.1.1 Concetti di base
Le reti di Petri costituiscono uno strumento espressivo che ben si presta alla modellizzazione ed all’analisi di sistemi concorrenti. Due sono sostanzialmente i motivi che le rendono utili in tale ambito. Da un lato le reti di Petri consentono di dare al modello di un sistema il rigore formale necessario sia per eliminare ogni fonte d’ambiguità nella
rappresentazione, sia per effettuare analisi e verifiche sul comportamento del sistema.
Dall’altro il formalismo delle reti di Petri è suscettibile di una rappresentazione grafica piuttosto spontanea.[1]
Un esempio di una possibile rappresentazione grafica di una rete di Petri è data in Fig. 35
In una rete di Petri gli elementi fondamentali sono: i posti, le marche (o token) contenuti all’interno dei posti, le transizioni, gli archi, i pesi degli archi. (Fig. 34)
I posti insieme alle marche definiscono lo stato del sistema. Le transizioni modificano lo stato della rete spostando le marche da un posto all’altro. Gli archi definiscono i collegamenti tra posti e transizioni. I pesi degli archi definiscono il numero di token che saranno spostati allo scattare di una transizione.
Da notare che non è possibile connettere posti a posti come transizioni a transizioni.
Per completezza diamo la definizione di preset e di postset. Preso un nodo n della rete (posto o transizione) il suo preset è l’insieme dei nodi dai quali parte un arco che arriva ad n;
il preset di n si indica con pre(n). Preso un nodo n della rete (posto o transizione) il suo postset è l’insieme dei nodi ai quali arriva un arco che parte da n; il postset si indica con post(n). (Fig. 36)
La rete si evolve con lo scattare delle transizioni. Una transizione può scattare se abilitata:
questo si verifica se tutti i posti del suo preset contengono un numero di token almeno pari al peso dell’arco che li connette alla transizione.
Lo scatto di una transizione provoca la rimozione da ogni posto del preset e l’aggiunta ad ogni posto del postset di un numero di token pari al peso degli archi che la collegano a tali posti. La marcatura di tutti i posti che non sono né di ingresso né di uscita per tale transizione rimane inalterata.(Fig. 37)[2]
Fig. 34 Elementi costitutivi di un rete di
Fig. 35 Esempio di una rete di petri
58 La regola di scatto non è sufficiente a determinare compiutamente l’evoluzione di una rete perché, in una generica marcatura, può accadere che più transizioni risultino abilitate allo scatto (e chiaramente se si sceglie di farne scattare certune o certe altre l’evoluzione futura della rete non è la stessa).[2] Il criterio di scelta è del tutto non deterministico. Questo criterio rispetta l’indipendenza degli eventi.
Pertanto due eventi che in uno stato possono verificarsi l’uno indipendentemente dall’altro vengono rappresentati da due transizioni della rete che possono avere luogo concorrentemente.[1]
All’interno di una rete possono venirsi a trovare le seguenti strutture modellistiche:
• Sequenza
• Conflitto
• Concorrenza
5.1.1.1 Sequenza
Due transizioni t1 e t2 si dicono in sequenza e t1 precede t2 in una data marcatura M quando,con t1 abilitata e t2 non abilitata, lo scatto di t1 abilita t2
5.1.1.2 Conflitto
Due transizioni t1 e t2 sono in conflitto strutturale se e solo se hanno almeno un posto d’ingresso in comune. Tuttavia, questo non è sufficiente per decidere se due transizioni sono realmente in conflitto fra loro. Due transizioni t1 e t2 si dicono in conflitto effettivo nella marcatura M se sono in conflitto strutturale, se sono abilitate entrambe in M ed il numero delle marche che i loro posti d’ingresso contengono non è sufficiente a soddisfare tutti i pesi degli archi che li collegano alle due transizioni. Il conflitto strutturale dipende dalla topologia della rete, il conflitto effettivo anche dalla marcatura
Fig. 36 Postset e preset
Fig. 37 Esempio di evoluzione di una rete di Petri
Fig. 38 Sequenza
Fig. 39 Conflitto
59 corrente. Si osservi che il conflitto strutturale non implica che possa verificarsi il conflitto effettivo (in Fig. 39 è raffigurata una situazione di conflitto effettivo)
5.1.1.3 Concorrenza
Due transizioni t1 e t2 sono fra loro in concorrenza strutturale quando non condividono alcun posto d’ingresso, cioè lo scatto di una delle due transizioni non disabilita l’altra. Si introduce, come nel caso del conflitto, il concetto di concorrenza effettiva, situazione che si presenta solo durante l’evoluzione della rete. Due transizioni t1 e t2 si dicono in concorrenza effettiva nella marcatura M se sono abilitate entrambe in M. Si osservi che la concorrenza strutturale implica che possa verificarsi quella effettiva.
5.2 Reti di petri ad alto livello o “colorate”
Nel complesso insieme delle reti di Petri è possibile annoverarne una tipologia nota come reti di petri colorate o dette ad alto livello, quest'insieme, si distingue profondamente dalle reti di Petri P/T ed hanno un potere di espressività di più alto livello. Infatti le reti di Petri P/T sono note come reti di basso livello in quanto queste rappresentano le funzionalità intrinseche del sistema stesso. Le reti colorate, invece, offrono la possibilità di effettuare una modellizzazione di livello differente, evidenziando cioè le particolarità sia dei livelli di funzionamento che delle differenti tipologie di elementi che compongono il sistema stesso.
Una particolare categoria di reti di petri ad alto livello sono quelle che supportano un linguaggio di programmazione orientato agli oggetti, questa è la tipologia di rete che è stata utilizzata per realizzare l’automa dei prelievi.
Fra le reti di petri P/T e quelle colorate sussiste la stessa differenza prensente tra un linguaggio di programmazione a basso livello come Assembler e uno di alto livello come il Java: nel linguaggio ad alto livello abbiamo funzionalità come i tipi di dati, utilizzo di array o liste, chiamate a funzione e definizione di oggetti (classi), che nell’Assembler sono del tutto assenti. In queste reti, infatti, è possibile andare a inserire token tipizzati: circoleranno nella rete token con un proprio tipo e valore. Si possono trovare, infatti, sia tipi primitivi come interi, caratteri o valori in virgola mobile sia tipi definiti dall’utente. Come vedremo nel tool di sviluppo per reti di Petri ad alto livello utilizzato, sarà possibile includere un qualunque oggetto definito da una classe Java.
In Fig. 41 è rappresentata una semplice rete di Petri ad alto livello. All’interno del posto di partenza troviamo la presenza di tre token di tipo intero. Sui due archi abbiamo come peso la variabile i, che è stata dichiarata come intero, questo significa che ad ogni scatto della transizione, questa porterà via un token di tipo intero dal suo preset e ne inserirà uno nel suo postset.
Un’altra caratteristica delle reti colorate che viene messa in evidenza in questa rete è la presenza di una condizione di scatto sulla transizione: in questo caso abbiamo un controllo sul valore dell’intero i se questo non supera il test la transizione non scatta; ovviamente allo scatto della transizione verranno spostati solo token che rispettano la condizione di guardia della transizione; in questo caso verrà spostato solo il token di valore 45.
Le caratteristiche presentate sono solo un piccolo sottoinsieme delle potenzialità di una rete di petri ad alto livello con supporto ad un linguaggio orientato ad oggetti; un maggior
Fig. 40 Concorrenza
Fig. 41 Esempio di rete ad alto livello
60 approfondimento riguardo queste funzionalità è affrontato nel paragrafo 5.3 dedicato al tool di sviluppo utilizzato.
5.3 Tool di sviluppo Renew (Reference Net Workshop) 5.3.1 Lo stato dell’arte e la scelta del tool di sviluppo
Come primo problema nell’affrontare la progettazione di una rete di Petri ad alto livello era quello di trovare un tool di sviluppo che permettesse di creare un’interfaccia tra la rete e il codice “convenzionale” come funzioni java o store procedure scritte in linguaggio PL/SQL.
Questo è un requisito irrinunciabile in quanto una rete che vive di vita propria isolata dal resto del software non ha nessun utilità pratica e rimane un mero studio di ricerca. Tale requisito base ha subito ristretto la cerchia dei tool papabili.
Come ulteriore scrematura si è considerato che fosse preferibile trovare un ambiente che permettesse di introdurre all’interno della rete codice più possibile simile ad un linguaggio di programmazione ad oggetti di ampia diffusione come il Java o il C++ per limitare i tempi sviluppo e poter sfruttare a pieno tutte le potenzialità di un linguaggio ad oggetti.
La scelta del linguaggio si è orientata verso Java per i seguenti motivi:
• Linguaggio ampiamente diffuso e ricco di documentazione
• Indipendenza del codice Java dalla piattaforma grazie all’utilizzo della virtual machine
• Libreria per la creazione di interfacce grafica integrata nel pacchetto di sviluppo JDK della Sun
• Facile integrazione con le store procedure presenti nel database Oracle
Dati questi requisiti, anche se è possibile trovare decine di tool di sviluppo (si rimanda al [3] per un elenco completo) con caratteristiche fra le più disparate, dopo un’analisi attenta la scelta si è orientata verso Renew. I motivi principali di questa scelta sono stati:
• Interfaccia completa con il linguaggio Java
• Ampia documentazione [5]
• Referente per supporto tecnico molto competente [4]
Il secondo e il terzo motivo potrebbero risultare banali ma c’è da sottolineare come questi tool di sviluppo siano più o meno tutti creati in ambiente di ricerca: sono stati creati ex novo veri e propri formalismi e linguaggi di programmazione per le rete di Petri che se non documentati a dovere e senza la possibilità di contattare uno degli sviluppatori per i necessari chiarimenti rendono tali tool del tutto inutilizzabili.
5.3.2 Presentazione del tool
Renew è un tool di sviluppo di reti di Petri ad alto livello con supporto al linguaggio di programmazione Java ed è stato sviluppato dal dipartimento di informatica dell’Università di Amburgo ed è giunto alla versione 2.1 che è risultata essere ormai stabile.
I principali punti di forza di Renew sono:
• È scritto completamente in Java quindi può girare su tutte le piattaforme
• Insieme al tool è possibile scaricare tutto il codice sorgente con possibilità di analizzare gli algoritmi utilizzati e modificarli o migliorarli secondo necessità
• All’interno di un rete Renew è possibile utilizzare un qualunque oggetto di una classe Java e si ricorda che esistono ormai classi Java anche open source che
61 risolvono i più disperati compiti. Questo implica poter riutilizzare codice già scritto e ridurre conseguentemente i tempi e i costi di sviluppo
5.3.3 Installazione del tool
In questo capitolo è data una breve panorama sull’installazione del tool di sviluppo Renew in un ambiente di lavoro con sistema operativo Windows. Per ogni eventuale approfondimento, per informazioni non esposte in questa sede e a riguardo altre piattaforme si rimanda alla consultazione del manuale d’uso di Renew [5]
5.3.3.1 Prerequisiti
Deve essere installata sul sistema la Java virtual machine versione 1.4 o superiore.
Suggerisco di scaricare da [6] la versione per sviluppatori “JDK 5.0 with Netbeans” che comprende oltre al compilatore Java anche un ambiente di sviluppo grafico gratuito (IDE) che può risultare utile per sviluppo di applicazioni Java collegate alla rete di Petri.
È necessario scaricare il codice eseguibile di Renew “the base package in jar format” da [7]
5.3.3.2 Installazione di base
Come primo passo dell’installazione è necessario estrarre l’archivio jar appena scaricato attraverso il seguente comando lanciato dal prompt dei comandi:
jar xf renew2.1base.jar
Una directory renew2.1 è creata nella directory di lavoro corrente.
Per comodità di lancio della piattaforma sotto ambiente windows è possibile eseguire, sempre da linea di comando, i seguenti comandi:
cd renew2.1/bin/win installrenew
Questi creeranno una serie di batch file di cui in prima analisi è interessante solo renew.bat il quale permette di lanciare il tool in maniera agevole.
È necessario prestare attenzione che la variabile di ambiente PATH includa il percorso dove è stato installato la JDK per la corretta esecuzione dello script e che il lancio del renew.bat avvenga direttamente da dentro la directory /bin/win.
5.3.4 Reference Nets
All’interno di questo paragrafo sono presentate le caratteristiche delle reti che si possono progettare con l’utilizzo di Renew. Si presentano, per primi, gli elementi base delle reti, successivamente, il linguaggio di inscrizione e le altre caratteristiche di questi reti che sono chiamate Reference nets.
5.3.4.1 Gli elementi base di una rete
All’avvio dell’ambiente Renew viene visualizzata la Renew Toolbox (Fig. 42) Nella parte bassa a sinistra di questa troviamo le icone per creare gli elementi base di una rete: posti, transizioni e archi.
Fig. 42 Renew Toolbox
62 5.3.4.1.1 Archi
Ci sono molti tipi di archi. Gli archi semplici per collegare transizione e posti tra di loro che sono caratterizzati da una sola freccia e il loro comportamento è quello standard:
aggiungono e rimuovono token da un posto. Gli archi test, caratterizzati da assenza di frecce, questo tipo di arco non causa alcun spostamento di token e serve per monitorare il valore assunto da un token. Ad esempio, possono risultare utili per leggere ad ogni transizione dei parametri costanti necessari per il resto della rete in elaborazione. I doppi archi (reverse arc), caratterizzati da doppia freccia, che semplicemente causano un doppio spostamento del token: è una scorciatoia per non dover creare due archi semplici. L’arco flessibile che permette la rimozione di più token con una sola transizione.(Fig. 43)
5.3.4.1.2 Posti
Esistono due tipi di posti: il posto semplice e quello virtuale. Il posto semplice si comporta come nelle reti di petri ad alto livello, accumula token arrivati dalle transizioni. Il posto virtuale non è altro che una copia di un posto semplice e durante l’evoluzione della rete conterrà gli stessi token del posto semplice di cui è copia. Il posto virtuale è utile per semplificare lo schema di una rete quando un certo token deve essere disponibile in più zone della rete: si evita di ingombrare lo schema della rete con archi inutili.
5.3.5 Il linguaggio di inscrizione
La reale potenza delle reti di alto livello è il linguaggio di inscrizione. Ogni elemento della rete può avere una inscrizione associata che, nel caso di Renew, sarà scritta in un linguaggio molto simile al Java. Tale linguaggio ha innumerevoli funzionalità che sono elencate nei paragrafi seguenti.
Da notare che per scrivere le iscrizioni all’interno del tool grafico è necessario fare click con il tasto destro del mouse sull’elemento al quale si vuole associare l’inscrizione.
L’inscrizione, una volta ultimata, può essere spostata all’interno della rete per far sì che il disegno rimanga il più possibile leggibile. Per capire a qual oggetto risulta associata ogni inscrizione, è sufficiente fare doppio click sull’inscrizione e sarà evidenziato l’elemento a cui questa è associata.
È possibile associare anche una etichetta ad ogni elemento della rete tramite il pulsante n presente in Fig. 42; questo nome serve solo per comodità di lettura della rete e viene inserito nel log di simulazione.
5.3.5.1 Espressioni di inizializzazione e tipizzazione di un posto
È possibile vincolare un posto ad ammettere al suo interno esclusivamente token di un certo tipo: questo si realizza scrivendo all’interno del posto il tipo permesso.
L’inizializzazione di un posto con un certo numero di valore si realizza semplicemente andando a scrivere nel posto i valori.
Da notare il token speciale [] che è il token vuoto senza tipo, coincide con il token delle reti di petri a basso livello.(Fig. 44)
Le inscrizioni sull’arco sono valutate nel momento in cui scatta la transizione: in Fig. 44 l’iscrizione dell’arco assegna al numero intero che verrà rimosso dal posto la variabile i.
5.3.5.2 Blocco dichiarazione
Per quanto riguarda la dichiarazione di variabili ci sono due opzioni: non dichiarare nessuna variabile o dichiararle tutte. Nel momento in cui dobbiamo dichiarare per necessità Fig. 43 Elementi di un rete
Fig. 44 Inizializzazione di un posto
63 un oggetto di una classe Java saremo costretti a dichiarare tutte le variabili all’interno della rete.
Il blocco per le dichiarazioni si crea attraverso il pulsante d presente in Fig. 42.
Come si vede dalla Fig. 45 basta elencare, come in un normale programma Java, tutte le variabili, c’è da sottolineare come sia possibile dichiarare oggetti appartenenti a classi Java. In Fig. 44 è dichiarato un oggetto Jframe e un oggetto Root.
Ovviamente è necessario importare le classi di cui vogliamo creare un oggetto attraverso la direttiva import.
Da notare, affinché non venga restituito un errore nel momento della dichiarazione, tutte le classi che si vogliono utilizzare devono essere incluse nella variabile di ambiente CLASSPATH di Java.
Nell’esempio di Fig. 44 per dichiarare l’oggetto Root dovrà essere incluso nel CLASSPATH l’archivio jar contenente il codice compilato dell’automa dei prelievi.
5.3.5.3 Inscrizioni delle transizioni
Ad un transizione è possibile associare tre tipi di inscrizioni: le inscrizione d’espressione, le inscrizione di guardia e le inscrizioni di azione. La prima ha uno scarso utilizzo pratico e ne trascuro la descrizione.
5.3.5.3.1 Inscrizione di guardia
Questo tipo di iscrizione ha come prefisso la parola riservata guard. Tale transizione può scattare solo quando tutte le sue inscrizioni guard risultano vere. Un esempio di tale inscrizione è raffigurato in Fig. 41.Questa inscrizione è utilizzata laddove è necessario porre una o più condizioni di scatto ad una transizione.
5.3.5.3.2 Inscrizione di azione
L’inscrizioni di azione hanno come prefisso la parola riservata action.
Queste inscrizioni è garantito che siano valutate ed eseguite una sola volta per ogni scatto della transizione associata. Sono molto utili per il calcolo dei token di uscita dalla transizione. In Fig. 46 è mostrata una transizione di azione denominata Attribuzione del Commercializzato la quale richiama una funzione membro Java dell’oggetto lo_l2j che ritorna come valore li_att che è il token trasferito nel postset della transizione. Da notare l’arco di test sulla sinistra che porta in una tupla i valori necessari allo scatto della transizione.
Un ulteriore particolarità della rete in figura è l’utilizzo del posto che contiene il token di valore 0 che è associato alla variabile go. Questo permette l’esecuzione una volta soltanto della transizione, se non fosse presente tale posto la transizione scatterebbe infinite volte perché l’arco di test sarebbe sempre soddisfatto.
5.3.5.4 Invocazione di funzioni
In Fig. 46 è visibile una rete nella quale si realizza l’invocazione di metodi Java esterni alla rete. La sintassi utilizzata è del tutto analoga a quella del linguaggio Java.
Da notare una particolarità: se mettiamo due dichiarazioni action associate alla stessa transizione,anche scritte in sequenza all’interno dello stessa casella di testo, non vi è alcuna garanzia che esse siano eseguite nell’ordine in cui sono state scritte. Il motore di Renew Fig. 45 Blocco dichiarazione
Fig. 46 Inscrizione di azione
64 selezionerà in maniera casuale quale eseguire per prima, quindi se deve essere rispettato l’ordine di alcune azioni si dovrà creare una sequenza di transizioni con inscrizioni di azione.
5.3.5.5 Tuple e liste
Una tupla è una lista di espressioni separate da virgole, racchiuse da parentesi quadre come, ad esempio, [1, ”abc”, 1.5]. Le tuple sono molto utili per raggruppare una serie di oggetti di tipo diverso in unico insieme. All’interno di questo progetto si farà un pesante uso delle tuple dovendo trasportare attraverso tutta la rete set di valori di tipo diverso.
Abbiamo già incontrato il token vuoto [] questo non è altro che una tupla vuota. Le tuple possono essere annidate: ad esempio [[1,2],[a,b,c]].
Le liste sono insieme di valori delimitati da parentesi graffe in Fig. 47 è presente la lista {1,2,3,4}. Renew permette di gestire le liste di lunghezza variabile in quanto ammette l’uso dell’operatore due punti (:) per ricavare la coda della lista: ad esempio {1,2,3,4}={hd:tl}
significa che hd è uguale a 1 mentre tl è uguale alla coda della lista cioè a {2,3,4}.
In Fig. 47 è rappresentata una rete che inverte la lista presente nel posto iniziale andando a dividere l’elemento di testa della lista dalla coda, mettendolo in coda alla lista risultato.
È possibile sia con le tuple che con le liste andare ad associare variabili ai singoli elementi di una lista: ad esempio se scriviamo {1,2,3,4}={a,b,c,f} associamo 1 alla variabile a, 2 alla variabile b ecc.
5.3.5.6 Transizioni manuali
Esiste una particolare inscrizione composta dalla sola parola riservata manual che rende la transizione attivabile manualmente. Questo può essere utile durante la simulazione della rete per far scattare la transizione da parte dell’utente. Per far scattare la transizione l’utente, durante la simulazione, dovrà fare un click con il tasto destro del mouse sulla transizione.
5.3.5.7 Creare oggetti net reference
Renew, come abbiamo detto è scritto totalmente in Java, questo ha comportato che ogni rete sia a sua volta un oggetto Java. Quindi è possibile, una volta disegnata la rete, andarla ad allocare come un qualunque altro oggetto Java.
Detto questo si prospettano due scenari:
• Date due reti a e b sarà possibile ad esempio creare in a una istanza della rete b
• Creare una istanza di una rete direttamente da un programma Java indipendente.
Il primo caso si realizza andando a creare una inscrizione con la parola riservata new
nella rete che crea un’istanza dell’altra.
L’oggetto rete appena creato può essere spostato come token all’interno della rete Fig. 47 Tuple e liste
Fig. 48 Rete che crea
un’istanza di un'altra rete Fig. 49 Rete othernet allocata
65 come un qualsiasi altro token; un esempio di tutto ciò è illustrato in Fig. 48, dove nella transizione in alto vengono create due istanze della rete othernet di Fig. 49 .
La sintassi completa per creare un istanza è: nome della variabile (alla quale verrà associato l’oggetto appena creato), un due punti (:) e la parola riservata new; ad esempio x:new othernet.
Un altro aspetto da evidenziare è che ogni istanza creata è un oggetto diverso: infatti la transizione in basso di Fig. 48 che ha un’inscrizione di guardia la quale controlla la differenza fra le due variabili x e y, risulta abilitata in quanto l’oggetto x e y sono due oggetti diversi.
Per quanto riguarda la gestione del tempo di vita dell’istanze create è da notare quanto segue. Una rete che è stata creata e non viene più referenziata da nessuna variabile non è detto che sia cancellata per garbage collection immediatamente: infatti una rete allocata in memoria sarà deallocata solo nel momento in cui, non essendo più referenziata da nessuna variabile, essa non avrà più nessuna transizione abilitabile.
Nel secondo scenario invece, cioè nel caso in cui si desideri creare un istanza di una rete direttamente da un programma Java indipendente, le operazioni da compiere sono più complesse.
Sfortunatamente dopo numerosi tentativi, attente consultazioni del manuale e diversi scambi di informazioni con il referente del progetto è risultato che la procedura, illustrata nel manuale, non funziona correttamente. È stato impossibile, quindi, andare a creare una istanza di una rete di Petri da codice Java. Inoltre sono venuto a conoscenza che tale procedura non è mai stata testata dagli sviluppatori del progetto ed è stata riportata sul manuale solo come potenzialità “teorica” del tool. Per quanto detto, ho deciso di non riportare le modalità illustratemi.
5.3.5.8 Canali di comunicazione
Nel paragrafo 5.3.5.7 è stata esposta la tecnica per la creazione di istanze di reti ma tale procedura senza la possibilità di scambio di informazioni tra una rete e l’altra sarebbe del tutto inutile. Infatti, una volta creata una istanza di una rete, è verosimile che questa abbia necessità di alcune informazioni provenienti dal suo creatore per evolvere in maniera corretta.
Dalla prospettiva opposta, sarà necessario, anche, che la rete creata ritorni dei valori alla rete padre come risultato della sua elaborazione.
Per fare tutto questo Renew mette a disposizione dei canali di comunicazione sincrona: cioè il mittente e il ricevente sono entrambi d’accordo nel partecipare alla comunicazione in un determinato momento.
Fig. 50 Canale sincrono all’interno di
una rete
Fig. 51 Rete mittente
Fig. 52 Rete destinatario bag
66 La comunicazione sincrona consiste nel sincronizzare due transizioni in modo tale che scattino allo stesso istante. Entrambe le due transizioni devono accordarsi sul nome del canale di comunicazione, sul numero e nome dei parametri da scambiarsi prima che la comunicazione possa essere stabilita.
Tale comunicazione può avvenire all’interno di una singola rete se, ad esempio, vogliamo trasportare informazioni da un punto all’altro di una rete senza dover tracciare un arco oppure si possono mettere in comunicazione due reti diverse. Ovviamente, nel secondo caso, per la rete mittente è necessario conoscere il nome della rete destinatario.
Il mittente deve creare una transizione chiamata downlink: che non è altro che una richiesta di comunicazione sincrona che la rete mittente pone alla rete destinatario. Una transizione di downlink è realizzata attraverso un’inscrizione composta da il nome della rete, un due punti (:) il nome del canale e un blocco opzionale di parametri racchiusi da parentesi tonde: ad esempio, rete_destinario:ch(1,’a’,3) tenta di comunicare con la rete_destinario attraverso il canale ch e di trasmettere i tre parametri tra tonde.
Il ricevente dovrà creare una transizione chiamata uplink che rappresenta l’attesa della rete ricevente per la comunicazione sincrona. Una transizione uplink è realizzata attraverso un’inscrizione composta da: un due punti (:), il nome del canale e un blocco opzionale di variabili racchiuse da parentesi tonde che sono associate ai parametri passati: ad esempio :ch(x,y,z).
Nel caso in cui si voglia realizzare la comunicazione all’interno della stessa rete si deve ricorrere, per la transizione downlink, alla parola riservata this che identifica la rete stessa.
In Fig. 50 sono rappresentate due transizioni una di downlink e l’altro di uplink per la comunicazione sincrona all’interno della stessa rete.
In Fig. 51 e Fig. 52 è realizzata una comunicazione sincrona fra due reti distinte: la rete mittente crea nella transizione a sinistra una istanza della rete bag e comunica sul canale
deposit due valori; nella transizione in basso a destra recupera tali valori depositati andando a richiedere un valore sul canale take; nella rete destinatario si vedono realizzate due transizioni di uplink. Da questo esempio si evince che la transizione di downlink non è necessariamente associata al mittente e quella di uplink al destinatario della comunicazione, piuttosto dobbiamo pensare di associare la transizione di downlink a quella rete che crea
Fig. 53 Configurazione a tempo di esecuzione
67 l’istanza dell’altra e quindi ne conosce il nome; mentre quella di uplink la associamo a chi è chiamato nella comunicazione ma non conosce il nome del chiamante.
5.3.6 Configurazioni e trucchi di sviluppo
Il tool Renew è altamente configurabile sono possibili due tipi di configurazioni una a tempo di esecuzione e una permanente. Quella a tempo di esecuzione si attua attraverso i menu della Renew toolbox ed è valida solo dalla modifica della configurazione fino alla chiusura del tool. Quella permanente si attua attraverso la modifica di due file di configurazione: uno riguardante il tool in generale e uno specifico per le procedure di log 5.3.6.1 Configurazione a tempo di esecuzione
Accedendo al menu SimulationÆConfigure Simulation… viene lanciata la schermata di configurazione di Fig. 53 nella quale sono presenti varie schede di configurazione. Non è questa la sede per la descrizione minuziosa di tutte le possibilità di configurazione ma è descritta solamente una delle opzioni più utili in fase di sviluppo.
Se la rete di Petri creata è collegata ad una o più funzioni Java esterne sarà necessario che ad ogni simulazione la rete di petri vada a caricare l’ultima versione compilate delle classi a cui sono associate tali funzioni. Per fare ciò è necessario spuntare la opzione Class reinit mode nella scheda Engine di Fig. 53.
5.3.6.2 Configurazione permanente
La configurazione permanente di una opzione si realizza andando a modificare due file di testo: renew.properties per quanto riguarda le opzioni in generale e il file log4j.properties per quanto riguarda i log. Questi file sono tutti contenuti nella directory renew2.1/config.
Una delle opzioni più utili in fase di sviluppo è abilitare una tipologia di logging detta di debug: questa andrà a rendere nella console dei prompt di comandi tutte le azione intraprese dal motore di Renew, in questo modo è facile ricavare eventuali errori.
Le stringhe che devono essere inserite all’interno del file log4j.properties sono:
log4j.logger.de.renew.shadow=DEBUG log4j.logger.de.renew.application=DEBUG
Tutte le informazioni di log, oltre ad essere mostrate a video sono memorizzate all’interno di due file: renew.log per quanto riguarda le azioni generali compiute dal tool di sviluppo e simulation.log per informazioni strettamente legate alla simulazione. Entrambi i file risiedono nella home_directory_utente/renewlogs.
Non è stata esposta la parte relativa alle reti di petri temporizzate e sono stati trascurati alcuni aspetti del tool di sviluppo Renew in quanto di scarso interesse per la realizzazione dell’automa dei prelievi. Per maggiori informazioni su queste parti omesse si rimanda al manuale [5].
Si è trascurata la descrizione dei menù delle Renew toolbox (Fig. 42) in quanto si ritengono auto esplicativi della loro funzione.