Questi meccanismi non sono standard, ma vengono implementati da kernel molto diffusi come per esempio Linux. Data la loro diffusione e il fatto che sono fra i pochi approcci a consentire l'utilizzo della memoria condivisa, introdurremo anche le IPC di System V, sebbene si discostino abbastanza dalla filosofia di Unix. Per quest'ultimo motivo non andremo però ad approfondire la sintassi e la semantica delle varie primitive, ma ne introdurremo solamente l'utilizzo.
System V individua ogni struttura che permette ai processi di comunicare tramite un identificatore unico nel sistema: in generale, due processi possono comunicare a patto di conoscere entrambi l'identificatore globale della struttura di IPC che intendono utilizzare. Tale valore, o ID, è ritornato dalle syscall usate per creare o per acquisire le strutture di IPC. Vedremo poi quali tecniche possono utilizzare i vari processi per ``concordare'' sull'identificatore della struttura di IPC da usare.
Ma passiamo ora ad analizzare i meccanismi di IPC di system V, cominciando con le code di messaggi. Una message queue è, come dice il nome, una coda di messaggi collegati fra loro ed accessibili tramite un identificatore di coda (queue ID). Per poter utilizzare una message queue, un processo deve utilizzare la primitiva msgget() per creare la coda (o collegarsi ad essa se già esiste).
Poichè le code di messaggi non sono accessibili tramite decrittori di file, le primitive di I/O di Unix non possono essere usate su di esse (e per questo le IPC di System V si discostano parecchio dagli standard Unix), quindi servono delle apposite primitive per accedere ad esse. Tali primitive sono msgctl() (equivalente ad ioctl), msgsnd() (equivalente a write()) e msgrcv() (equivalente a read()). Si invita a riferirsi ai manfile per vedere la sintassi e la semantica di tali primitive.
Oltre alla comunicazione a scambio di messaggi, System V implementa anche il paradigma a memoria comune, discostandosi quindi dal classiso modello di programmazione di Unix. Le primitive di IPC di System V utilizzano un'interfaccia omogenea, quindi anche semafori e regioni di memoria comune saranno creabili e controllabili tramite primitive *get() e *ctl().
In particolare, un processo può creare un semaforo (o collegarsi ad esso se già esiste) tramite la syscall semget().
Una volta che un processo ha acquisito un semaforo tramite semget(), è in grado di operare su di esso (incrementando o decrementando il suo contatore di valore arbitrario) tramite la primitiva semop().
Per quanto riguarda invece la memoria comune, un processo può ottenere l'identificatore di una zona di memoria comune tramite la primitiva shmget(), mapparla nel proprio spazio di memoria privato tramite shmat() ed iliminare tale mapping tramite shmdt().
Rimane ora da vedere come processi fra loro indipendenti possano concordare su un ID comune da utilizzare per comunicare. Come detto, l'ID è ritornato dalle primitive *get:
#include<sys/types.h>
int *get(key_t key, ..., int flags);
|
Argomenti in ingresso :
Valore restituito :
Il modo più semplice per fare questo è far generare l'ID dal sistema quando uno dei processi genera la struttura di IPC, e farlo salvare in un luogo noto a tutti i processi che devono comunicare tramite tale struttura di IPC (tipicamente nel file system). Gli altri processi che vogliono accedere a tale struttura dovranno quindi andare a reperire l'ID in tale locazione convenzionale. Un esempio di tale soluzione è quindi il seguente:
Un'altra soluzione può essere quella di embeddare una chiave (key) che identifichi univocamente la struttura di IPC nel codice dei vari processi: tipicamente un header file incluso da essi conterrà la definizione della chiave come costante. A questo punto la funzione *get() convertira' la chiave in un ID. Il problema con questo approccio è che vari set fra loro indipendenti di processi cooperanti possono tentare di usare la stessa chiave per compiti diversi. Questo è inevitabile, ma bisogna comunque evitare che si generino situazioni di inconsistenza: in pratica, è auspicabile che la seconda applicazione che cerca di utilizzare la stessa chiave si blocchi, senza interferire con la prima che ha utilizzato tale chiave. Questo è possibile procedendo nel seguente modo: un solo processo per applicazione crea la struttura di IPC, specificando i flag IPC_CREAT | IPC_EXCL che fanno generare una condizione di errore se la struttura già esiste.
La terza soluzione è invece basata sull'utilizzo della funzione ftok(), che permette di ricostruire l'ID a partire da una chiave conosciuta dai vari processi (composta da un pathname e da un carattere, il project ID).
Notare che se invece i processi che devono comunicare fra loro sono legati da una relazione padre/figlio, il probelma non sussiste perchè la struttura può essere creata dal padre, e l'ID viene ereditato dal figlio.