Colección de citas famosas - Slogan de motivación - Memoria C * * *Ejemplo de comunicación de proceso compartido.

Memoria C * * *Ejemplo de comunicación de proceso compartido.

Ejemplos de mmap()

A continuación se darán dos ejemplos del uso de mmap(): El ejemplo 1 ilustra que dos procesos logran * * * comunicación de memoria al mapear archivos ordinarios. El ejemplo 2 ilustra que los procesos padre-hijo logran; mapeo anónimo Implementar * * * memoria compartida. Hay muchas cosas interesantes sobre la llamada al sistema mmap(). El siguiente es un ejemplo del uso de mmap () para asignar archivos ordinarios para lograr la comunicación entre procesos. Damos ejemplos para ilustrar las características y precauciones de mmap() para lograr * * * compartir memoria.

Ejemplo 1: dos procesos realizan * * * comunicación de memoria asignando archivos ordinarios.

El ejemplo 1 contiene dos subprogramas: map_normalfile1.c y map_normalfile2.c compilan dos programas, y los archivos ejecutables son map_normalfile1 y map_normalfile2 respectivamente. Los dos programas especifican el mismo archivo a través de parámetros de línea de comando para lograr * * * comunicación entre procesos en modo de memoria compartida. Map_normalfile2 intenta abrir el archivo normal especificado por el argumento de la línea de comando, asigna el archivo al espacio de direcciones del proceso y escribe en el espacio de direcciones asignado. Map_normalfile1 asigna el archivo especificado por el argumento de la línea de comando al espacio de direcciones del proceso y luego lee el espacio de direcciones asignado. De esta manera, dos procesos especifican el mismo archivo a través de parámetros de línea de comando, realizando la comunicación entre procesos en modo * * * de uso compartido de memoria.

Aquí hay dos códigos de programa:

/* - map_normalfile1.c - */

# include & ltsys/mman

p>

# incluir & ltsys/types h & gt;

# incluir & ltfcntl.h & gt

# incluir & ltunistd.h &. gt

estructura typedef {

Nombre del personaje[4];

int edad

};

principal (int argc, char** argv) //Asignar archivos ordinarios a la memoria compartida:

{

int fd, I;

人* p_map

Temperatura de carbonización;

fd=open(argv[1], O_CREAT|O_RDWR|O_TRUNC, 00777);

lseek(fd, sizeof(people)*5 - 1, SEEK_SET);

Escribir (fd, "", 1);

p_map = (personas*) mmap( NULL, tamaño de (personas)*10, PROT_READ| PROT_WRITE , MAP_SHARED, fd, 0);

Cerrar(fd

temp = ' a

for(I = 0;i<10;i++ )

{

temp+= 1;

memcpy( ( *(p_map+i)). nombre y temperatura,

( *(p_map+i)).

edad = 2I;

}

printf(" inicializar sobre \ n ");

dormir(10); munmap(p_map,sizeof(people)* 10);

printf(" umap ok \ n ");

}

/* - map_normalfile2.c - */

# incluir & ltsys/mman

# incluir & ltsys/types

# incluir & ltfcntl. .h & gt

# include & ltunistd.h & gt

estructura typedef {

Nombre del personaje[4];

int edad

}Personas;

main(int argc, char** argv) //Asignar archivos ordinarios a la memoria compartida:

{

int fd, I;

humano * p_map

fd=open( argv[1], O_CREAT|O_RDWR, 00777);

p_map = ( personas*)mmap(NULL,tamañode(personas)*10,PROT_READ|PROT_WRITE,MAP_SHARED,fd,0);

for(I = 0;i<10;i++)

{

printf(" nombre:% s edad % d;\n",(*(p_map+i)). nombre, (*(p_map+i)). edad); p>}

munmap(p_map, sizeof(people)* 10);

}

Map_normalfile1.c primero define una estructura de datos de personas (los datos La estructura se utiliza aquí porque los datos en el área de memoria * * * a menudo tienen un formato fijo, que está determinado por cada proceso de comunicación, y la estructura es generalmente representativa). Map_normfile1 primero abre o crea un archivo y establece la longitud del archivo al tamaño de la estructura de cinco personas. Luego, a partir de la dirección de retorno de mmap(), configure 10 estructuras humanas. Luego, el proceso duerme durante 10 segundos, espera a que otros procesos mapeen el mismo archivo y finalmente lo desasigna.

Map_normfile2.c simplemente asigna un archivo, lee estructuras de 10 personas en el formato de estructura de datos de personas desde la dirección devuelta por mmap(), genera los valores leídos y luego los desasigna.

Compile los dos programas en archivos ejecutables map_normalfile1 y map_normalfile2 respectivamente, y luego ejecútelos en la terminal.

/map_normalfile2 /tmp/test_shm, los resultados de salida del programa son los siguientes:

Reinicialización

umap normal

Después de generar la inicialización desde map_normalfile1, antes de generar umap está bien , ejecutar map_normalfile2 /tmp/test_shm en otra terminal producirá el siguiente resultado (el resultado está ligeramente ordenado para ahorrar espacio):

Nombre: b edad 20; c edad 21 nombre: d edad 22; ; nombre: e 23 años; nombre: f 24 años; nombre: g 25 años; nombre: k 29 años;

Después de que map_normalfile1 genere umap ok, ejecutar map_normalfile2 generará los siguientes resultados:

Nombre: b edad 20; nombre: c edad 21 nombre: d edad 22; 23; Nombre: f Edad 24;

Nombre: Edad 0; Nombre: Edad 0; Nombre: Edad 0; que se puede extraer de los resultados de la ejecución

1. La longitud del contenido del archivo mapeado final no excederá el tamaño inicial del archivo en sí, es decir, la asignación no puede cambiar el tamaño del archivo;

p>

2. Disponible El tamaño del espacio de direcciones efectivo para la comunicación del proceso generalmente está limitado por el tamaño del archivo mapeado, pero no está completamente limitado por el tamaño del archivo. El archivo abierto se trunca a tamaños de estructura de cinco personas y la estructura de datos de 10 personas se inicializa en map_normalfile1. Cuando llama a map_normalfile2 en el momento adecuado (después de inicializar map_normalfile1 y antes de que se genere umap ok), encontrará que map_normalfile2 generará todos los valores de la estructura de 10 personas.

Nota: En Linux, la protección de la memoria se basa en páginas. Incluso si el archivo mapeado tiene un tamaño de solo un byte, el kernel asigna una memoria del tamaño de una página para el mapeo. Cuando el archivo mapeado es más pequeño que el tamaño de la página, el proceso puede acceder al tamaño de la página sin errores comenzando en la dirección de retorno de mmap(); sin embargo, si se accede al espacio de direcciones fuera de la página, se producirá un error, como se describe; más abajo. Por lo tanto, el tamaño del espacio de direcciones efectivo disponible para la comunicación entre procesos no puede exceder la suma del tamaño del archivo y el tamaño de una página.

3. Una vez asignado el archivo, el proceso que llama a mmap() accede a la dirección de retorno de una determinada área de memoria, liberándose temporalmente del impacto del archivo en el disco. Todas las operaciones que devuelven espacio de direcciones a mmap() sólo tienen sentido en la memoria. Solo después de llamar a munmap () o msync () se puede volver a escribir el contenido correspondiente en la memoria en el archivo del disco, y el contenido escrito aún no puede exceder el tamaño del archivo.

Ejemplo 2: Los procesos padre-hijo comparten memoria mediante mapeo anónimo.

# incluir & ltsys/mman .

# incluir & ltsys/types .

# incluir & ltfcntl.h &. gt

# include & ltunistd.h & gt

estructura typedef {

Nombre del personaje[4];

int edad

p>

}Personas;

main(int argc, char** argv)

{

int I;

Personas* p_map

Temperatura de carbonización;

p_map=(personas*)mmap(NULL, sizeof(people)*10, PROT_READ|PROT_WRITE, MAP_SHARED|MAP_ANONYMOUS, -1, 0);

if(fork() == 0)

{

Dormir(2);

para (I = 0;i<5;i++)

printf("niño leído: La edad de esta %d persona es %d\n ", i+1, (*(p_map+i)).Age

(*p_mapa). age = 100;

munmap(p_map, sizeof(people) * 10); //En realidad, cuando el proceso finaliza, se desasigna automáticamente.

salir();

}

temp = ' a

for(I = 0;i<5;i++)

{

temp+= 1;

memcpy((*(p_map+i)).nombre&temperature,2);

(*(p_map +yo)). Edad = 2I;

}

Dormir(5);

printf(" el padre leyó: las primeras personas, su edad es %d\n ", (*p_map).age);

printf(" umap \ n ");

munmap( p_map, sizeof(people)* 10);

printf(" umap ok \ n ");

}

Al inspeccionar la salida del programa, me di cuenta de que el proceso padre-hijo disfruta de memoria anónima:

Lectura infantil: La edad de una persona es 20

Sublectura: Las edades de dos personas son 21

Lectura infantil: Las edades de tres personas son todas 22

Lectura infantil: Las edades de estas 4 personas son 23 años

Los niños leen: Las edades de las 5 personas son 24

Los padres leen: La edad de la primera persona es 100

umap

umap es normal

Volver al principio

4. Acceda a la dirección del remitente de mmap( )

Como se mencionó anteriormente, la estructura de ejecución del ejemplo. Como se mencionó, Linux utiliza un mecanismo de administración de páginas. Para archivos normales asignados por mmap(), el proceso agregará un espacio a su propio espacio de direcciones, y el tamaño del espacio se especifica mediante el parámetro len de mmap(). Tenga en cuenta que es posible que el proceso no pueda acceder de manera eficiente a todo el espacio recién agregado. El tamaño efectivo de la dirección a la que puede acceder un proceso depende del tamaño de la parte asignada del archivo. En pocas palabras, el número mínimo de páginas que pueden acomodar el tamaño de la parte asignada del archivo determina el espacio de direcciones al que un proceso puede acceder efectivamente desde la dirección devuelta por mmap(). Más allá de este tamaño de espacio, el núcleo enviará diferentes señales al proceso dependiendo de la gravedad del exceso. Los ejemplos pueden ser los siguientes:

Nota: La parte asignada del archivo, no el archivo completo, determina la cantidad de espacio al que puede acceder el proceso. Además, si especifica una parte desplazada del archivo, se debe tener cuidado de que sea un múltiplo entero del tamaño de la página.

El siguiente es un ejemplo de acceso a un espacio de direcciones mapeado de proceso:

# include & ltsys/mman

# include & ltsys/types <. /p>

# include & ltfcntl.h & gt

# include & ltunistd.h & gt

estructura typedef {

Nombre del personaje[4 ];

int edad

}persona;

main(int argc, char** argv)

{

int fd, I;

int tamaño de página, desplazamiento

persona * p _ map

PAGESIZE = sysconf(_ SC _ PAGESIZE);

printf("el tamaño de página es %d\n ",tamaño de página);

fd = open(argv[1], O_CREAT|O_RDWR|O_TRUNC, 00777);

lseek( fd,pagesize*2-100,SEEK_SET);

write(fd,"",1);

offset = 0; //aquí offset = 0 compilado en Versión 1; Desplazamiento = tamaño de página compilada en la Versión 2.

p_map = (people*)mmap(NULL, tamaño de página*3, PROT_read | PROT_write, map_share, fd, offset)

Cerrar (FD );

for(I = 1;i<10;i++)

{

(*(p _ map+pagesize/sizeof(people)* I-2)). edad = 100;

printf("página de acceso %d over\n ",I);

(*(p_map+pagesize/sizeof(people)* I-1 )) . Edad = 100;

printf("Visitando la página %d, ahora empezando a visitar la página %d\n ", I, I+1); _ mapa+tamaño de página/tamaño de(personas)* I)). edad = 100;

printf("acceder a la página %d over\n ",I+1);

}

munmap(p_map, sizeof(personas )* 10);

}

Como se menciona en el programa, el programa está compilado en dos versiones, lo que se refleja principalmente en los diferentes tamaños de las partes de mapeo de los archivos. El tamaño del archivo está entre una página y dos páginas (tamaño: tamaño de página*2-99). La parte asignada de la versión 1 es el archivo completo. La parte asignada de la versión 2 es el tamaño del archivo menos la parte restante de una página. es más pequeño que el tamaño de la página (tamaño:tamañodepágina-99). El programa intenta acceder a cada límite de página y ambas versiones intentan asignar tamaño de página*3 bytes en el espacio de proceso.

El resultado de la versión 1 es el siguiente:

El tamaño de página es 4096

Finaliza la visita a la página 1

Finaliza la visita a la página 1 y comienza ahora Visita la página 2

Fin de la visita a la página 2

Fin de la visita a la página 2

Fin de la visita a la página 2, ahora comienza a visitar página 3

Error de bus //El archivo de mapeo cubre dos páginas en el espacio de proceso. En este punto, el proceso intenta acceder a la tercera página.

El resultado de la versión 2 es el siguiente:

El tamaño de la página es 4096

Finaliza la visita a la página 1

Finaliza la visita a la página 1 y comienza ahora Acceder a la página 2

Error de bus //El archivo de mapeo sobrescribe una página en el espacio de proceso. En este punto, el proceso intenta acceder a la segunda página.

Conclusión: Es muy conveniente utilizar la llamada al sistema mmap() para implementar la comunicación entre procesos, y la interfaz en la capa de aplicación es muy simple. El área del mecanismo de implementación interna involucra la administración del almacenamiento de Linux y el contenido del sistema de archivos. Puede consultar las estructuras de datos importantes relevantes para profundizar su comprensión. Más adelante en este tema, se presentará la implementación del uso compartido de memoria system v***.

Datos de referencia

[1] Understanding the Linux Kernel, Second Edition, escrito por Daniel P. Bovet y Marco Cesati, se centra en cada tema y el contenido es claro.

[2] Programación de redes UNIX Volumen 2: Comunicación entre procesos, autor W.Richard Stevens, traductor: Yang·, Tsinghua University Press. Mmap() explicado en detalle.

[3] "Análisis de escenario del código fuente del kernel de Linux (1)", Mao y Hu, Zhejiang University Press, proporciona un análisis del código fuente relacionado con mmap().

[4]manual de mmap()