Un altro modo per scambiare dati tra processi UNIX è la memoria condivisa. Ogni memoria condivisa ha una chiave che la identifica in modo univoco. Quando un processo vuole utilizzare una memoria condivisa deve attaccarla al proprio spazio di indirizzamento, quando non desidera più utilizzarla può successivamente staccarla anche se essa continuerà ad esistere indipendentemente da ogni processo, a meno che non venga esplicitamente distrutta.

Quando un processo genera un figlio tramite la chiamata fork(), esso eredita le aree condivise di memoria attaccate al padre. Se un processo termina, le relative aree di memoria attaccate vengono staccate ma nono distrutte (a meno che non venga specificato).

Le chiamate shm* per gestire la memoria condivisa e i loro parametri sono spesso simili a quelle msg* che gestiscono le code. Ecco un esempio di due processi fratelli che scambiano numeri tramite l’utilizzo di un’area di memoria condivisa:

Codice sorgente:

#include <stdio.h>
#include <stdlib.h>

// librerie necessarie per l'utilizzo della memoria condivisa tra processi
#include <sys/ipc.h>
#include <sys/shm.h>

#define MAX_NUMBERS 10

void scrittore(int id);
void lettore(int id);

int main()
{
        int id_shm;

        // crea l'area di memoria condivisa
        id_shm = shmget(IPC_PRIVATE, sizeof(int)*(MAX_NUMBERS+1), IPC_CREAT|IPC_EXCL|0600);
        if (id_shm == -1)
        {
                printf("Errore nella chiamata shmget().n");
                exit(1);
        }

        // crea un primo processo figlio che scrive nella memoria condivisa
        if (fork() != 0)
        	// il processo padre attende il termine del primo figlio
        	wait(NULL);
        else
        	// il primo processo figlio scrive nella memoria condivisa e termina
        	scrittore(id_shm);

        // crea un secondo processo figlio che legge dalla memoria condivisa
        if (fork() != 0)
        	// il processo padre attende il termine del secondo figlio
        	wait(NULL);
        else
        	// il secondo processo figlio legge dalla memoria condivisa e termina
        	lettore(id_shm);

        // distrugge l'area di memoria condivisa e termina
        shmctl(id_shm, IPC_RMID, NULL);
        exit(0);
}

void scrittore(int id)
{
	int *p;
	int numero, q=0;
	printf("n**Processo Scrittore:n");

	// la chiamata shmat riporta l'indirizzo di memoria a cui è stata attaccata la memoria condivisa
	p = (int *)shmat(id, NULL, 0);
	if (p == (int *)-1)
	{
		printf("Errore nella chiamata shmat().n");
		exit(1);
	}

	do
	{
		printf("nScrivi un numero da inserire ('0' per terminare): ");
		scanf("%d",&numero);
		if (numero == 0)	break;
		p[q+1] = numero;
		q++;
		printf("nNumero inserito: %dn",numero);
	}	while (q < MAX_NUMBERS);

	// nel primo slot scrive la quantità di numeri depositati
	p[0] = q;
	exit(0);
}

void lettore(int id)
{
	int *p;
	int i, q=0;
	printf("n**Processo Lettore:n");

	// collega la memoria condivisa con lo spazio di indirizzamento, in sola lettura tramite SHM_RDONLY
	p = (int *)shmat(id, NULL, SHM_RDONLY);
	if (p == (int *)-1)
	{
		printf("Errore nella chiamata shmat().n");
		exit(1);
	}

	// legge quanti numeri ci sono nell'area condivisa
	q = p[0];

	for (i = 1; i <= q; i++)
		printf("%d ", p[i]);
	printf("n");
	exit(0);
}

About OpenProgrammers

Programmatore per passione. Mi piace condividere qualsiasi idea o informazione utile, per questo motivo ho realizzato il blog.