2010-02-09 10 views
7

Quiero asignar e inicializar un trozo bastante grande de memoria contigua (~ 1GB), luego marcarlo como proceso de solo lectura y horquilla múltiple (digamos varias docenas) secundarios que lo usarán, sin hacer sus propias copias de la memoria (la máquina no tendrá suficiente memoria para esto).¿Es esta una forma segura de compartir memoria de solo lectura con procesos secundarios?

Estoy en lo cierto al pensar que si malloc la memoria como de costumbre, a continuación, marca como de sólo lectura con mprotect(addr, size, PROT_READ) y luego fork, esto permitirá que los procesos secundarios para utilizar con seguridad la memoria sin causar que se va a copiar? (Siempre que me asegure de que nada intente escribir en la memoria asignada después de la llamada mprotect).

editar: Gracias por todas las respuestas.

Una pregunta de seguimiento - Yo pensaba usar shmget, pero pensé que utiliza mm y por lo tanto se limitaría a las asignaciones más pequeñas (véase el Restrictions section of this page). por ejemplo, /proc/sys/kernel/shmmax es 32MB en el servidor que estoy usando este. Pero quiero 1GB de memoria contigua. ¿Me equivoco sobre esta limitación?

Respuesta

7

man mprotect

La aplicación requerirá que addr ser un múltiplo del tamaño de página devuelto por sysconf().

El comportamiento de esta función no se especifica si la asignación no se estableció mediante una llamada al mmap().

  1. mprotect sólo funciona en las páginas, no rangos de tamaños arbitrarios, por lo que, en general, malloc es inapropiada. posix_memalign puede ayudar, pero ...
  2. Si bien puede trabajar en su sistema en el momento presente, que shoud nomprotect cualquier cosa que usted hizo no mmap mismo. Use mmap(0, pages*sysconf(_SC_PAGESIZE), PROT_READ|PROT_WRITE, MAP_SHARED|MAP_ANONYMOUS, -1, 0) en su lugar.
+0

Ah, gracias, obviamente no leí la página del manual de mprotect lo suficiente. –

+0

@dherefromhere 'MAP_SHARED | MAP_ANONYMOUS' aquí funciona para compartir desde un padre pre-bifurcado con cualquier elemento secundario. Si quieres compartir entre procesos arbitrarios, saca el 'MAP_ANONYMOUS' y dale un FD real en vez de' -1'; este FD puede venir de 'abrir' un archivo en el disco o de' shm_open'. – ephemient

+0

La página del manual de linux para mprotect hace notar "En Linux, siempre es legal llamar a mprotect() en cualquier dirección en un espacio de direcciones de procesos ..." http://linux.die.net/man/2/mprotect –

0

Mi comprensión es sí, ya que Linux utiliza un mecanismo de copia sobre escritura para las páginas de memoria pasadas a un proceso secundario.

3

No tiene razón porque cualquiera de los procesos secundarios puede llamar al mprotect() para eliminar la protección y comenzar a escribir allí. Si las páginas no se han copiado, violaría los principios de fork().

Incluso si funciona de esa manera que la copia en escritura se utiliza para los procesos de horquilla, no calculo cualquier lugar en normas que lo indique (POSIX no digo que es copia en escritura, por ejemplo).

En lugar de utilizar un comportamiento no estándar, puede usar medidas estándar para compartir memoria. Por ejemplo, la memoria compartida POSIX con shm_open y consecuente mmap (como se señaló en el comentario y se explica en su post por ephemient). El descriptor de archivo se conservará mediante bifurcación.

+0

Gracias. según la edición que estaba planeando usar 'shmget' pero pensé que era limitado en el tamaño de la asignación que podría hacer. –

+2

Diría que 'shm_open' es más seguro: le da un identificador de archivo a' mmap', en oposición a 'shmget' que le da un identificador arbitrario a' shmat', y ya he explicado por qué debería usar 'mmap' en mi respuesta. (Las dos API, a pesar de sus nombres similares, provienen de diferentes herencias y operan de manera muy diferente.) – ephemient

+0

@ephemient, sí, gracias por señalar esto. –

1

Usted está haciendo una suposición de que el núcleo haría copia en escritura optimización y no copiar las páginas mprotect -ed. Sin embargo, no lo esperaría. malloc -la memoria tiene todo tipo de metadatos flotando alrededor de ella- guardas páginas, etc. etc. y solo Ulrich Drepper sabe lo que sucede dentro de libc :)

Probablemente sería más fácil y seguro preparar los datos en un archivo de disco y ellos mmap en todos los procesos, o simplemente vaya a la ruta normal de POSIX shm_open.

+0

Gracias. según la edición que estaba planeando usar 'shmget' pero pensé que era limitado en el tamaño de la asignación que podría hacer. –

0

Podrías hacerlo de esa manera.

Una alternativa es usar mmap().

Otra alternativa es utilizar la memoria compartida POSIX (shm_open()); la otra alternativa principal es la memoria compartida del Sistema V (shmget(), shmat()). Una de las ventajas de los sistemas formales de memoria compartida es que el proceso principal puede crear la memoria y luego el proceso no relacionado podría conectarse a ella, si eso fuera beneficioso.

+0

Gracias. según la edición que estaba planeando usar 'shmget' pero pensé que era limitado en el tamaño de la asignación que podría hacer. –

+1

@therefromhere: es posible que deba ajustar la configuración del kernel (shmmax o tamaños relacionados), pero IBM Informix Dynamic Server usa shmget() para asignar trozos de múltiples gigabytes de memoria compartida si le indica que lo haga. –

2

No hay necesidad de marcarlo como de solo lectura, solo haga que sus procesos secundarios lo dejen en paz.

Si ni el padre ni el hijo lo escriben, debe seguir siendo compartido. Si alguna vez no quieres cambiarlo, está bien.

Si desea escribir, querrá usar mmap con MAP_SHARED.

Cuestiones relacionadas