Memoria condivisa
La memoria condivisa è una memoria condivisa tra due o più processi. Tuttavia, perché abbiamo bisogno di condividere la memoria o qualche altro mezzo di comunicazione?
Per ribadire, ogni processo ha il proprio spazio di indirizzi, se un processo vuole comunicare con alcune informazioni dal proprio spazio di indirizzi ad altri processi, allora è possibile solo con le tecniche IPC (inter process communication). Come già sappiamo, la comunicazione può avvenire tra processi correlati o non correlati.
Di solito, la comunicazione tra processi correlati viene eseguita utilizzando pipe o named pipe. La comunicazione di processi non correlati (ad esempio, un processo in esecuzione in un terminale e un altro processo in un altro terminale) può essere eseguita utilizzando Named Pipes o tramite le comuni tecniche IPC di Shared Memory e Message Queues.
Abbiamo visto le tecniche IPC di pipe e named pipe e ora è il momento di conoscere le restanti tecniche IPC, cioè memoria condivisa, code di messaggi, semafori, segnali e mappatura della memoria.
In questo capitolo, sapremo tutto sulla memoria condivisa.
Sappiamo che per comunicare tra due o più processi, utilizziamo la memoria condivisa ma prima di utilizzare la memoria condivisa cosa è necessario fare con le chiamate di sistema, vediamo questo:
Crea il segmento di memoria condivisa o usa un segmento di memoria condivisa già creato (shmget ())
Collega il processo al segmento di memoria condivisa già creato (shmat ())
Scollega il processo dal segmento di memoria condivisa già collegato (shmdt ())
Operazioni di controllo sul segmento di memoria condivisa (shmctl ())
Esaminiamo alcuni dettagli delle chiamate di sistema relative alla memoria condivisa.
#include <sys/ipc.h>
#include <sys/shm.h>
int shmget(key_t key, size_t size, int shmflg)
La chiamata di sistema precedente crea o alloca un segmento di memoria condivisa System V. Gli argomenti che devono essere passati sono i seguenti:
Il first argument, key,riconosce il segmento di memoria condivisa. La chiave può essere un valore arbitrario o uno che può essere derivato dalla funzione di libreria ftok (). La chiave può anche essere IPC_PRIVATE, significa eseguire processi come server e client (relazione genitore e figlio), cioè comunione tra processi correlati. Se il client desidera utilizzare la memoria condivisa con questa chiave, deve essere un processo figlio del server. Inoltre, il processo figlio deve essere creato dopo che il genitore ha ottenuto una memoria condivisa.
Il second argument, size, è la dimensione del segmento di memoria condivisa arrotondata al multiplo di PAGE_SIZE.
Il third argument, shmflg,specifica i flag di memoria condivisa richiesti come IPC_CREAT (creazione di un nuovo segmento) o IPC_EXCL (utilizzato con IPC_CREAT per creare un nuovo segmento e la chiamata non riesce, se il segmento esiste già). È necessario passare anche le autorizzazioni.
Note - Fare riferimento alle sezioni precedenti per i dettagli sulle autorizzazioni.
Questa chiamata restituirà un identificatore di memoria condivisa valido (utilizzato per ulteriori chiamate di memoria condivisa) in caso di successo e -1 in caso di errore. Per conoscere la causa del fallimento, controlla con la variabile errno o la funzione perror ().
#include <sys/types.h>
#include <sys/shm.h>
void * shmat(int shmid, const void *shmaddr, int shmflg)
La chiamata di sistema di cui sopra esegue l'operazione di memoria condivisa per il segmento di memoria condivisa di System V, cioè allegando un segmento di memoria condivisa allo spazio degli indirizzi del processo chiamante. Gli argomenti che devono essere passati sono i seguenti:
The first argument, shmid,è l'identificatore del segmento di memoria condivisa. Questo id è l'identificatore della memoria condivisa, che è il valore di ritorno della chiamata di sistema shmget ().
The second argument, shmaddr,è specificare l'indirizzo da allegare. Se shmaddr è NULL, il sistema sceglie per impostazione predefinita l'indirizzo adatto per collegare il segmento. Se shmaddr non è NULL e SHM_RND è specificato in shmflg, l'attacco è uguale all'indirizzo del multiplo più vicino di SHMLBA (Lower Boundary Address). In caso contrario, shmaddr deve essere un indirizzo allineato alla pagina in cui si verifica / inizia l'allegato della memoria condivisa.
The third argument, shmflg, specifica i flag di memoria condivisa richiesti come SHM_RND (arrotondando l'indirizzo a SHMLBA) o SHM_EXEC (consente l'esecuzione del contenuto del segmento) o SHM_RDONLY (allega il segmento a scopo di sola lettura, per impostazione predefinita è di lettura-scrittura) o SHM_REMAP (sostituisce la mappatura esistente nell'intervallo specificato da shmaddr e continua fino alla fine del segmento).
Questa chiamata restituirà l'indirizzo del segmento di memoria condivisa collegato in caso di successo e -1 in caso di errore. Per conoscere la causa del fallimento, controlla con la variabile errno o la funzione perror ().
#include <sys/types.h>
#include <sys/shm.h>
int shmdt(const void *shmaddr)
La chiamata di sistema di cui sopra esegue l'operazione di memoria condivisa per il segmento di memoria condivisa del Sistema V per staccare il segmento di memoria condivisa dallo spazio di indirizzi del processo chiamante. L'argomento che deve essere passato è:
L'argomento, shmaddr, è l'indirizzo del segmento di memoria condivisa da scollegare. Il segmento da scollegare deve essere l'indirizzo restituito dalla chiamata di sistema shmat ().
Questa chiamata restituirà 0 in caso di successo e -1 in caso di fallimento. Per conoscere la causa del fallimento, controlla con la variabile errno o la funzione perror ().
#include <sys/ipc.h>
#include <sys/shm.h>
int shmctl(int shmid, int cmd, struct shmid_ds *buf)
La chiamata di sistema di cui sopra esegue l'operazione di controllo per un segmento di memoria condivisa System V. È necessario passare i seguenti argomenti:
Il primo argomento, shmid, è l'identificatore del segmento di memoria condivisa. Questo id è l'identificatore della memoria condivisa, che è il valore di ritorno della chiamata di sistema shmget ().
Il secondo argomento, cmd, è il comando per eseguire l'operazione di controllo richiesta sul segmento di memoria condivisa.
I valori validi per cmd sono -
IPC_STAT- Copia le informazioni dei valori correnti di ogni membro di struct shmid_ds nella struttura passata indicata da buf. Questo comando richiede l'autorizzazione di lettura per il segmento di memoria condivisa.
IPC_SET - Imposta l'ID utente, l'ID gruppo del proprietario, i permessi, ecc. Puntati dalla struttura buf.
IPC_RMID- Contrassegna il segmento da distruggere. Il segmento viene distrutto solo dopo che l'ultimo processo lo ha scollegato.
IPC_INFO - Restituisce le informazioni sui limiti e sui parametri della memoria condivisa nella struttura indicata da buf.
SHM_INFO - Restituisce una struttura shm_info contenente informazioni sulle risorse di sistema consumate dalla memoria condivisa.
Il terzo argomento, buf, è un puntatore alla struttura della memoria condivisa chiamata struct shmid_ds. I valori di questa struttura verrebbero usati per set o get come da cmd.
Questa chiamata restituisce il valore a seconda del comando passato. In caso di successo di IPC_INFO e SHM_INFO o SHM_STAT restituisce l'indice o l'identificatore del segmento di memoria condivisa o 0 per altre operazioni e -1 in caso di errore. Per conoscere la causa del fallimento, controlla con la variabile errno o la funzione perror ().
Consideriamo il seguente programma di esempio.
Crea due processi, uno per la scrittura nella memoria condivisa (shm_write.c) e un altro per la lettura dalla memoria condivisa (shm_read.c)
Il programma esegue la scrittura nella memoria condivisa tramite il processo di scrittura (shm_write.c) e la lettura dalla memoria condivisa mediante il processo di lettura (shm_read.c)
Nella memoria condivisa, il processo di scrittura, crea una memoria condivisa di dimensione 1K (e flag) e allega la memoria condivisa
Il processo di scrittura scrive 5 volte gli alfabeti da "A" a "E" ciascuno di 1023 byte nella memoria condivisa. L'ultimo byte indica la fine del buffer
Il processo di lettura legge dalla memoria condivisa e scrive sullo standard output
Le azioni di processo di lettura e scrittura vengono eseguite simultaneamente
Dopo il completamento della scrittura, il processo di scrittura si aggiorna per indicare il completamento della scrittura nella memoria condivisa (con la variabile completa in struct shmseg)
Il processo di lettura esegue la lettura dalla memoria condivisa e viene visualizzato sull'output fino a quando non riceve l'indicazione del completamento del processo di scrittura (variabile completa nella struttura shmseg)
Esegue il processo di lettura e scrittura per alcune volte per semplificazione e anche per evitare loop infiniti e complicare il programma
Di seguito è riportato il codice per il processo di scrittura (Scrittura nella memoria condivisa - File: shm_write.c)
/* Filename: shm_write.c */
#include<stdio.h>
#include<sys/ipc.h>
#include<sys/shm.h>
#include<sys/types.h>
#include<string.h>
#include<errno.h>
#include<stdlib.h>
#include<unistd.h>
#include<string.h>
#define BUF_SIZE 1024
#define SHM_KEY 0x1234
struct shmseg {
int cnt;
int complete;
char buf[BUF_SIZE];
};
int fill_buffer(char * bufptr, int size);
int main(int argc, char *argv[]) {
int shmid, numtimes;
struct shmseg *shmp;
char *bufptr;
int spaceavailable;
shmid = shmget(SHM_KEY, sizeof(struct shmseg), 0644|IPC_CREAT);
if (shmid == -1) {
perror("Shared memory");
return 1;
}
// Attach to the segment to get a pointer to it.
shmp = shmat(shmid, NULL, 0);
if (shmp == (void *) -1) {
perror("Shared memory attach");
return 1;
}
/* Transfer blocks of data from buffer to shared memory */
bufptr = shmp->buf;
spaceavailable = BUF_SIZE;
for (numtimes = 0; numtimes < 5; numtimes++) {
shmp->cnt = fill_buffer(bufptr, spaceavailable);
shmp->complete = 0;
printf("Writing Process: Shared Memory Write: Wrote %d bytes\n", shmp->cnt);
bufptr = shmp->buf;
spaceavailable = BUF_SIZE;
sleep(3);
}
printf("Writing Process: Wrote %d times\n", numtimes);
shmp->complete = 1;
if (shmdt(shmp) == -1) {
perror("shmdt");
return 1;
}
if (shmctl(shmid, IPC_RMID, 0) == -1) {
perror("shmctl");
return 1;
}
printf("Writing Process: Complete\n");
return 0;
}
int fill_buffer(char * bufptr, int size) {
static char ch = 'A';
int filled_count;
//printf("size is %d\n", size);
memset(bufptr, ch, size - 1);
bufptr[size-1] = '\0';
if (ch > 122)
ch = 65;
if ( (ch >= 65) && (ch <= 122) ) {
if ( (ch >= 91) && (ch <= 96) ) {
ch = 65;
}
}
filled_count = strlen(bufptr);
//printf("buffer count is: %d\n", filled_count);
//printf("buffer filled is:%s\n", bufptr);
ch++;
return filled_count;
}
Fasi di compilazione ed esecuzione
Writing Process: Shared Memory Write: Wrote 1023 bytes
Writing Process: Shared Memory Write: Wrote 1023 bytes
Writing Process: Shared Memory Write: Wrote 1023 bytes
Writing Process: Shared Memory Write: Wrote 1023 bytes
Writing Process: Shared Memory Write: Wrote 1023 bytes
Writing Process: Wrote 5 times
Writing Process: Complete
Di seguito è riportato il codice per il processo di lettura (lettura dalla memoria condivisa e scrittura sullo standard output - File: shm_read.c)
/* Filename: shm_read.c */
#include<stdio.h>
#include<sys/ipc.h>
#include<sys/shm.h>
#include<sys/types.h>
#include<string.h>
#include<errno.h>
#include<stdlib.h>
#define BUF_SIZE 1024
#define SHM_KEY 0x1234
struct shmseg {
int cnt;
int complete;
char buf[BUF_SIZE];
};
int main(int argc, char *argv[]) {
int shmid;
struct shmseg *shmp;
shmid = shmget(SHM_KEY, sizeof(struct shmseg), 0644|IPC_CREAT);
if (shmid == -1) {
perror("Shared memory");
return 1;
}
// Attach to the segment to get a pointer to it.
shmp = shmat(shmid, NULL, 0);
if (shmp == (void *) -1) {
perror("Shared memory attach");
return 1;
}
/* Transfer blocks of data from shared memory to stdout*/
while (shmp->complete != 1) {
printf("segment contains : \n\"%s\"\n", shmp->buf);
if (shmp->cnt == -1) {
perror("read");
return 1;
}
printf("Reading Process: Shared Memory: Read %d bytes\n", shmp->cnt);
sleep(3);
}
printf("Reading Process: Reading Done, Detaching Shared Memory\n");
if (shmdt(shmp) == -1) {
perror("shmdt");
return 1;
}
printf("Reading Process: Complete\n");
return 0;
}
Fasi di compilazione ed esecuzione
segment contains :
"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
Reading Process: Shared Memory: Read 1023 bytes
segment contains :
"BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB
BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB
BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB
BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB
BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB
BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB
BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB
BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB
BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB
BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB
BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB
BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB"
Reading Process: Shared Memory: Read 1023 bytes
segment contains :
"CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC
CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC
CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC
CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC
CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC
CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC
CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC
CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC
CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC
CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC
CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC
CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC"
Reading Process: Shared Memory: Read 1023 bytes
segment contains :
"DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD
DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD
DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD
DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD
DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD
DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD
DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD
DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD
DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD
DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD
DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD
DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD"
Reading Process: Shared Memory: Read 1023 bytes
segment contains :
"EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE
EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE
EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE
EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE
EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE
EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE
EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE
EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE
EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE
EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE
EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE
EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE"
Reading Process: Shared Memory: Read 1023 bytes
Reading Process: Reading Done, Detaching Shared Memory
Reading Process: Complete