|
Appunti informatica |
|
Visite: 1458 | Gradito: | [ Picolo appunti ] |
Leggi anche appunti:Il flusso elaborativoIl flusso elaborativo Qualsiasi programma può venire codificato in un linguaggio I device driverI device driver Sempre più difficile: dopo avere affrontato i TSR (pag. 169) Impiego del costrutto monitorImpiego del costrutto monitor XII) Scrivere una applicazione |
Impiego del costrutto monitor
XII) Scrivere una applicazione concorrente che implementi mediante un monitor il problema della gestione di un'unità a disco a teste mobili (secondo l'algoritmo dell'ascensore).
Descrizione: Il costrutto monitor rappresenta un meccanismo di alto livello per implementare una risorsa gestore. In generale occorre definire, oltre alla risorsa da gestire, una struttura dati supplementare che contenga informazioni sullo stato della risorsa gestita. Una o più variabili di tipo condition vengono poi utilizzate per bloccare o sbloccare selettivamente i processi che competono per il controllo della risorsa, ciascuno in funzione della verifica (o meno) di una opportuna condizione di sincronizzazione. Nel caso specifico, la libreria Monitor usata nei programmi precedenti è stata leggermente modificata in modo da supportare l'uso di una Wait con Priorità (è possibile comunque non specificare alcuna priorità, in tal caso la Wait su Condition si comporta esattamente come in un monitor senza priorità). Il programma seguente implementa il problema della gestione di un'unità a disco a testine mobili secondo l'algoritmo dello SCAN (altrimenti detto dell'Ascensore): il disco viene percorso da un estremo all'altro nelle direzioni SU (dalla traccia più esterna a quella più interna) e GIU (dalla traccia più interna a quella più esterna) e vengono servite le richieste di accesso al disco nell'ordine in cui si incontrano muovendosi lungo la direzione corrente; arrivati ad un estremo si inverte la direzione. Per ottimizzare le operazioni, si è inoltre fatto in modo che la direzione venga invertita qualora non si abbiano altre richieste di servizio nella direzione di percorrenza corrente (algoritmo LOOK). Si noti che per evitare il fenomeno della starvation non vengono servite richieste supplementari (rispetto alla prima) relative ad una traccia che si sta già servendo.
PMonitor.H
#include <stdio.h>
#include <sys/wait.h>
#include "semafori.h"
#define MAX_PROC (long)10 //Numero massimo di processi in coda su ogni Condition
typedef struct Monitor;
//Definizione di MACRO per l'accesso ai semafori del Monitor
#define MUTEX 0 //Il primo semaforo è sempre il Mutex
#define INITIALIZE(M,S,V) Init_Sem(M->ID_Sem,S,V)
#define WAIT(M,S) Wait_Sem(M->ID_Sem,S)
#define SIGNAL(M,S) Signal_Sem(M->ID_Sem,S)
#define AWAITING(M,S) Awaiting_Sem(M->ID_Sem,S)
#define ENTER_MONITOR(M) WAIT(M,MUTEX) //Implementazione della Entry
#define LEAVE_MONITOR(M) SIGNAL(M,MUTEX)
void Create_Monitor(Monitor*, int); //Semaforo Mutex e variabili Conditions vengono allocati
void Destroy_Monitor(Monitor*); //Semaforo Mutex e variabili Conditions vengono deallocati
void Wait_Cond(Monitor*, int, int = 1); //Emula la Wait (con priorità) su una variabile Condition
void Signal_Cond(Monitor*, int); //Emula la Signal su una variabile Condition
PMonitor.C
#include "pmonitor.c"
void Create_Monitor(Monitor* M, int N_Conditions)
M->Priority=(int*)shmat(ID_Buf, 0, 0); //Il segmento allocato viene annesso al segmento dati
//del processo al primo indirizzo disponibile così come
//specificato dal sistema
if (M->Priority==(int*)-1)
//Priority è gestito come una coda di priorità: ogni volta che un processo si pone in attesa sul Monitor, //aggancia a questo vettore la sua priorità. Il Monitor poi provvede a riordinarne in modo crescente gli
//elementi in modo che in coda a Priority ci sia sempre la priorità più alta (minimo 1)
for(int i=0; i<N_Conditions; i++) Priority[i*MAX_PROC]=i*MAX_PROC;
//In Priority[i*MAX_PROC] c'è il puntatore all'ultimo elemento del segmento i-esimo del vettore, ovvero
//il segmento che si riferisce alla (i+1)esima variabile condition
key_t Key_Sem=IPC_PRIVATE; //Chiave del gruppo di semafori
M->ID_Sem=semget(Key_Sem, N_Conditions+1, IPC_CREAT|0664);
if (M->ID_Sem==-1)
void Destroy_Monitor(Monitor* M)
void Wait_Cond(Monitor* M, int ConditionID, int P)
//Se il processo arriva QUI significa che è quello a priorità massima!
M->Priority[Zero]--; //e cancella la sua priorità da Priority
void Signal_Cond(Monitor* M, int ConditionID)
LOOK.H
#include "pmonitor.h"
#define TRACCE (long)1000
enum DIREZIONE ;
typedef struct Ascensore;
void Init_Ascensore(Ascensore*); //Inizializza l'Ascensore
void Start_Monitor(Monitor*); //Inizializza il Monitor
void Stop_Monitor(Monitor*); //Elimina il Monitor
void Richiesta(int, Monitor*, Ascensore*); //Richiesta di accesso al disco
void Accesso(int, Ascensore*); //Accesso ad una traccia
void Rilascio(Monitor*, Ascensore*); //Rilascio del disco
LOOK.C
#include "look.h"
#define DIREZIONE_SU 1
#define DIREZIONE_GIU 2
void Init_Ascensore(Ascensore* A)
void Start_Monitor(Monitor* M)
void Stop_Monitor(Monitor* M)
void Richiesta(int destinazione, Monitor* M, Ascensore* A)
void Accesso(int destinazione, Ascensore* A)
void Rilascio(Monitor* M, Ascensore* A)
} else
}
Programma XII.C
#include "look.h"
#define DIM sizeof(Ascensore) //Dimensione dell'area di memoria condivisa
#define NUM_PROC 10 //Numero di processi che eseguono accessi
void main()
Ptr_Buf=(Ascensore*)shmat(ID_Buf, 0, 0); //Il segmento allocato viene annesso al segmento dati
//del processo al primo indirizzo disponibile così come
//specificato dal sistema
if (Ptr_Buf==(Ascensore*)-1)
Init_Ascensore(Ptr_Buf); //Inizializzazione dell'Ascensore
//----- CREAZIONE DEL MONITOR -----
Monitor M;
Start_Monitor(&M);
//----- GENERAZIONE FIGLI CHE PRODUCONO GLI ACCESSI -----
for(i=0; i<NUM_PROC; i++) else if (!pid)
} //End For NUM_PROC
//----- SINCRONIZZAZIONE DEL PADRE CON I FIGLI -----
for(i=0; i<NUM_PROC; i++)
//----- DISTRUZIONE DEL MONITOR -----
Stop_Monitor(&M);
//----- RILASCIO BUFFER DI MEMORIA CONDIVISA -----
shmctl(ID_Buf, IPC_RMID, 0);
Appunti su: |
|