|
Semafori in ADA |
4
Implementazione4
Uso4
Download codice semafori ed esempi (file .zip)4
Supporto Tecnico
|
|
Il package usr_semaphore, realizzato da Saltarelli Ettore come progetto di Sistemi per l'elaborazione dell'informazione II nel corso dell'A.A: 1997/98, definisce i semafori a conteggio e i semafori privati. Un semaforo è un'istanza di un tipo task semaphore le cui entry sono:
Task body semaphore is disp : integer; again : boolean := true; begin if n < 0 then raise INVALID_SEMAPHORE_VALUE; end if; disp := n; while again loop select when disp > 0 => accept P; disp := disp - 1; or accept V; disp := disp + 1; or accept Init (d : in integer) do disp := d; end; or accept Close; again := false; or delay infinite; again := false; end select; end loop; end; Il tipo semaphore è riservato e limitato, per cui il programmatore può richiamare le entry solo attraverso le apposite procedure definite nel package. Queste procedure sono di due classi: una implementa i semafori a conteggio e l'altra i semafori privati. Per quanto riguarda i semafori a conteggio le procedure accettano come parametro l'istanza del task semaphore. Il codice relativo alle quattro procedure per operare con i semafori a conteggio è: -- procedura P procedure P (s : in out semaphore) is begin s.P; end; -- procedura V procedure V (s : in out semaphore) is begin s.V; end; -- procedura Init: --definisce la disponibilita' di un semaforo procedure Init (s : in out semaphore; d : in integer) is begin if d < 0 then raise INVALID_SEMAPHORE_VALUE; end if; s.Init (d); end; -- procedura Close: --termina il task associato al semaforo procedure Close (s : in out semaphore) is begin s.Close; end; Qualche parola in più meritano i semafori privati. A differenza della PrivV, che può essere eseguita da qualsiasi task, la PrivP può essere eseguita soltanto dal task proprietario del semaforo. Bisogna quindi associare ad ogni processo il proprio semaforo ed a tale scopo si definisce una tavola di semafori privati in cui ogni elemento è un record di due campi: un identificatore del task proprietario (tipo Task_ID definito nel package ADA.Task_Identification) ed un puntatore ad un semaforo. type access_semaphore is access semaphore; type t_sem_descriptor is record ID : Task_ID := Null_Task_ID; sem : access_semaphore := null; end record; descriptor_table : array (1..max_priv_sem) of t_sem_descriptor; ID_NOT_FOUND : constant := 0; Ci sono poi due funzioni per la gestione della descriptor_table: -- funzione find_ID_in_table: --ritorna la posizione di id nella descriptor_table --oppure ID_NOT_FOUND se non e' presente function find_ID_in_table (id : in Task_ID) return integer is found : boolean := false; i : integer := 1; begin while (i <= max_priv_sem) and (not found) loop if (descriptor_table(i).sem /= null) then if (descriptor_table(i).sem'terminated) then descriptor_table(i).ID := Null_Task_ID; descriptor_table(i).sem := null; end if; end if; if descriptor_table(i).ID = id then found := true; else i := i + 1; end if; end loop; if found then return i; else return ID_NOT_FOUND; end if; end; -- funzione find_ID: --se id e' Null_Task_ID innalza INVALID_TASK_ID, altrimenti --se e' presente, ritorna la posizione di id nella --descriptor_table, altrimenti se c'e' un posto libero ne --inizializza il contenuto e ne ritorna la posizione, --altrimenti innalza l'eccezione FULL_PRIVATE_SEMAPHORE_TABLE function find_ID (id : in Task_ID) return integer is pos : integer; begin if id = Null_Task_ID then raise INVALID_TASK_ID; end if; pos := find_ID_in_table (id); if pos = ID_NOT_FOUND then pos := find_ID_in_table (Null_Task_ID); if pos = ID_NOT_FOUND then raise FULL_PRIVATE_SEMAPHORE_TABLE; end if; descriptor_table(pos).ID := id; descriptor_table(pos).sem := new semaphore; end if; return pos; end;
Infine, le quattro procedure utilizzabili dall'utente sono: -- procedura PrivP procedure PrivP is curr_ID : Task_ID; pos : integer; begin curr_ID := Current_Task;-- ritorna il proprio indice pos := find_ID (curr_ID); P (descriptor_table(pos).sem.all); end; -- procedura PrivV procedure PrivV (id : in Task_ID) is pos : integer; begin pos := find_ID (id); V (descriptor_table(pos).sem.all); end; -- procedura PrivInit: --definisce la disponibilita' del semaforo privato procedure PrivInit (id : in Task_ID; d : in integer) is pos : integer; begin pos := find_ID (id); Init (descriptor_table(pos).sem.all, d); end; -- procedura PrivClose: --termina il task associato al semaforo privato e libera la --posizione nella descriptor_table procedure PrivClose is curr_ID : Task_ID; pos : integer; begin curr_ID := Current_Task;-- ritorna il proprio indice pos := find_ID_in_table (curr_ID); if pos /= ID_NOT_FOUND then Close (descriptor_table(pos).sem.all); descriptor_table(pos).ID := Null_Task_ID; descriptor_table(pos).sem := null; end if; end;
|
|
|
|
L'uso dei semafori in un programma ADA non è diverso da quello noto dalla teoria della programmazione concorrente. Naturalmente, il primo passo è quello di includere il package contenente i semafori attraverso le istruzioni: with usr_semaphore; use usr_semaphore; Poi, per definire un semaforo, bisogna definire un'istanza del tipo semaphore con la dichiarazione: <nome_semaforo> : semaphore(<num_intero>); in cui <nome_semaforo> è il nome che si vuole dare all'istanza e <num_intero> è il numero che identifica il massimo numero di accessi contemporanei alla sezione critica (1 per semafori binari e valori maggiori di 1 per semafori a conteggio). A questo punto è possibile utilizzare le P e le V per risolvere i problemi di programmazione concorrente. Alcuni esempi sull'uso di questo package sono inclusi nel file .zip scaricabile dall'apposito link all'inizio della pagina; essi sono:
|
|
|
|
Per eventuali problemi, chiarimenti e/o suggerimenti scrivete a: clemente@csr.unibo.it |
|