Makefile make -f altronome
Compilazione=>comando:make oppure per compilare con un file “altronome”.
target: dipendenze
[tab] comando di sistema
• Per compilazione separata:
file.o : file.cpp file.h => se il file dipende da file.h e file.cpp
gcc -c file.cpp
• Per unire i vari moduli
eseguibile: obj1.o … objN.o
gcc -o eseguibile obj1.o … objN.o make clean
• Chiudere sempre il makefile con un clean da invocare prima della compilazione con un
clean: rm -f *.o rm -f *~ rm -f *kdev*
esempio:
start: lib.o main.o
g++ -o start lib.o main.o
lib.o: lib.cpp lib.h
g++ -c lib.cpp
main.o: main.cpp lib.h
g++ -c main.cpp
Shared Memory
Tutte le risorse IPC (interprocess comunication) tra cui Shared memory (SHM) semafori (SEM) e code di
messaggi (MSG) sono indentificate da una chiave univoca IPC KEY che può essere generata tramite
key_t ftok(char * path, char id) Restituisce una chiave combinando degli elementi con il carattere
indicato come secondo argomento.
get ctl
Le 2 primitive comuni sono e get restituisce il descrittore della risorso e ctl (control) permette di
effettuare delle operazioni sulla risorsa.
int …get (key_t key, …, int flag);
key ftok() flag
Dove è una chiave generata con e indica il metodo di creazione e i permessi, ad esempio:
IPC_CREAT|0664
int …ctl (int desc, …, int cmd, …);
desc cmd
Dove è il descrittore della risorsa e indica il comando da eseguire
Comandi di controllo da shell:
ipcs <-m|-s|-q>
visualizza tutte le risorse allocate
ipcrm <shm|sem|msg> <IPC_ID>
rimuove una data struttura noto il suo idenatificatore
Utilizzo SHM:
Creazione della SHM=>Collegamento alla SHM=>Uso della SHM=>Scollegamento della SHM=>
Eliminazione della SHM
Creazione:
int shmget(key_t key, int size, int flag)
dimensione della memoria
size intero che specifica la modalità di creazione e dei permessi di accesso (IPC_CREAT, IPC_EXCL,
flag
permessi)
Esempio:
key_t chiave = 40;
int ds_shm;
ds_shm = shmget(chiave, 1024,IPC_CREAT | IPC_EXCL |0664);
Collegamento:
void* shmat(int shmid, const void *shmaddr,int flag)
Collega il segmento di memoria allo spazio di indirizzamento del chiamante.
shmid : identificatore del segmento di memoria
shmaddr : indirizzo dell’area di memoria del processo chiamante al quale collegare il segmento di memoria condivisa. Se è un
puntatore nullo il segmento di memoria è il primo disponibile e viene selezionato dal sistema.
Controllo:
int shmctl(int ds_shm, int cmd, struct shmid_ds * buff)
Invoca l’esecuzione di un comando su una SHM
ds_shm : descrittore della memoria condivisa su cui si vuole operare
cmd
: specifica del comando da eseguire:
IPC_STAT, IPC_SET
IPC_RMID: da eliminare, rimuove solo quando non vi sono più processi attaccati
SHM_LOCK: impedisce che il segmento venga swappato o paginato
buff : puntatore ad una struttura di tipo shmid_ds con eventuali parametri per i comandi IPC_STAT e IPC_SET
Sys Call:
Ogni processo ha un’unico identificatore di processo (Process Identifier: PID), intero tra 0 e 30000
Un processo ottiene il suo pid attraverso la chiamata di sistema :
int getpid();
Un processo ottiene il pid del padre attraverso la chiamata di sistema :
int getppid();
Sospende (transizione stato Blocked) un processo per un certo numero di secondi:
sleep(int sec);
La creazione di nuovi processi è gestita mediante la chiamata di sistema:
int fork(void);
°il figlio eredita gli stessi valori delle variabili, i descrittori agli stessi file aperti, e anche il Program Counter!
°le modifiche apportate alle proprie variabili da uno dei due processi non sono visibili all’altro.
Per comunicare al padre lo stato di terminazione dei figli:
int wait(int *stato);
Un processo termina con la chiamata di sistema exit:
exit(0);
L’unico modo in cui un programma può essere eseguito da Unix è che il processo esistente invii una chiamata
di sistema exec. Esistono varie versioni della exec :
int execlp (char *nomefile, char *arg0, .., char *argn,(char *) 0);
int execl (char *pathname, char *arg0, .., char *argn,(char *) 0);
Una system call che crea un processo senza copiare l’immagine dal padre al figlio:
vfork();
Semafori
Creazione ed inizializzazione di un semaforo:
key, nsems, semflg);
int semget(key_t int int
semid, semnum, cmd, …);
int semctl(int int int
key_t chiave_sem=IPC_PRIVATE;
Esempio:
//richiesta di 2 semafori ed inizializzazione
sem=semget(chiave_sem,2,IPC_CREAT|0664);
//Inizializzazione dei due semafori
semctl(sem,0,SETVAL,val1); semctl(sem,1,SETVAL,val2);
Operazioni sui semafori, wait e signal:
wait(semaphore
void s)
{ s.value--;
if (s.value<0)
{ s.queue.insert(Process);
suspend(Process);
}
} signal(semaphore
void s)
{ s.value++;
if (s.value<=0)
{ s.queue.remove(Process);
wake-up(Process);
}
}
Semaphore operations:
semid, *sops, nsops);
int semop(int struct sembuf unsigned
ognuno degli nsops elementi, riferiti dal puntatore sops, specifica ’operazione da compiere sul semaforo. L’operazione è descritta da
una struttura, struct sembuf.
wait
• sem_op < 0 : wait_for_zero
• sem_op==0 :
signal
• sem_op > 0 :
Rimozione di una struttura semaforica:
semctl(id_sem, num_sem ,IPC_RMID);
ne di una signal
La variabile num_sem in questo caso viene ignorata
Semafori Implementazione:
Ricorda che la struct sembuf contiene i seguenti campi:
unsigned short sem_num; // numero di semaforo
short sem_op; // operazione da compiere
short sem_flg; // flags
Wait_Sem(int,
static void int);
Signal_Sem
static void (int,int);
Queue_Sem
static int (int,int); //restituisce il num di processi in attesa su un semaforo
Wait_Sem(int
void id_sem, int numsem)
{ struct sembuf sem_buf;
sem_buf.sem_num=numsem;
sem_buf.sem_flg=0;
sem_buf.sem_op=-1;
semop(id_sem,&sem_buf,1); //semaforo rosso
} Queue_Sem(int
int id_sem, int numsem)
{ return (semctl(id_sem,numsem,GETNCNT,NULL)); }
Signal_Sem
void (int id_sem,int numsem)
{ struct sembuf sem_buf;
sem_buf.sem_num=numsem;
sem_buf.sem_flg=0;
sem_buf.sem_op=1;
semop(id_sem,&sem_buf,1); //semaforo verde
}
Monitor:
Permette la gestione di processi in base a delle condizioni, La sospensione di un processo nel caso in cui la
condizione non sia verificata, avviene utilizzando un nuovo tipo di variabile, detta variabile di tipo condition:
var_cond x;
sulla quale possono essere compiute signal e wait
x.wait; x.signal;
provoca la sospensione del processo fino a che un altro processo esegue
Ovviamente se non vi è alcun processo in attesa sulla variabile x, la signal non ha alcun effetto.
Signal and wait:
Sia P un processo sospeso su una variabile condition x e Q il processo che esegue la signal su tale variabile
Signal_and_wait prevede che il processo P risvegliato riprenda immediatamente l'esecuzione e che Q venga
sospeso;
Signal_and_urgent_wait:
Prevede che il processo Q abbia la priorità su ogni altro processo che intende entrare nel monitor Ciò si può
ottenere sospendendo il processo Q su un'apposita coda (urgent_queue).
Signal and continue:
detto anche wait and notify privilegia il processo segnalante rispetto al segnalato. Il processo Q segnalante
prosegue la sua esecuzione, mantenendo l'