Compartir memoria entre procesos mediante el uso de mmap()

5 minutos de lectura

Estoy en Linux 2.6. Tengo un entorno donde 2 procesos simulan (usando memoria compartida) el intercambio de datos a través de una implementación simple del modo de paso de mensajes.

Tengo un proceso de cliente (bifurcado del padre, que es el servidor) que escribe una estructura (mensaje) en una región mapeada en memoria creada (después de la bifurcación) con:

message *m = mmap(NULL, sizeof(message), PROT_READ|PROT_WRITE, MAP_SHARED|MAP_ANONYMOUS, -1, 0)

Luego, este puntero se escribe en una cola (en forma de una lista vinculada) en otra área de memoria compartida que es común para el servidor y el proceso del cliente (porque se creó antes de la bifurcación con el mismo código anterior). Esta área es luego leída por el servidor que obtiene el puntero al mensaje y lo procesa.

El problema es que *m se crea después de la bifurcación() y cuando el proceso del servidor intenta acceder a la ubicación de memoria señalada, aparece un error de segmentación. ¿Es posible adjuntar esa región de memoria a la bifurcación POST del servidor, después de que el cliente la crea?

NOTA: No quiero asignar el puntero al mensaje antes de bifurcarlo (y luego compartirlo antes con el servidor) porque normalmente no sé cuántos mensajes quiere enviar el cliente al servidor, y también puede haber más de 1 proceso de cliente, por lo que me gustaría crear un nuevo bloque de memoria compartida solo cuando un cliente necesita enviar un mensaje y desasignarlo después de que el servidor haya recibido ese mensaje.

NOTA: Esto es para fines académicos: sé que esta no es la mejor manera de resolver este problema, pero solo necesito seguir este camino.

¡Gracias por adelantado!

avatar de usuario
Maxim Egorushkin

¿Es posible adjuntar esa región de memoria a la bifurcación POST del servidor, después de que el cliente la crea?

MAP_ANONYMOUS|MAP_SHARED solo se puede acceder a la memoria mapeada mediante el proceso que hace eso mmap() llamada o sus procesos secundarios. No hay forma de que otro proceso mapee la misma memoria porque no se puede hacer referencia a esa memoria desde otro lugar ya que es anónimo.

Utilizando shm_open() llamar es posible crear llamado memoria compartida a la que se puede hacer referencia y mapear mediante procesos no relacionados.

  • ¡Gracias! solía shm_open() y luego mmap() con el fd dado, resolvió el problema parcialmente. ¿Es posible cambiar el nombre (usando rename()) la cadena de “etiqueta” que proporciono a shm_open() después de que el fd está mapeado? Intenté hacer esto pero luego, cuando trato de usar shm_open() de otro proceso que usa la etiqueta renombrada, obtengo un “Error de autobús” en tiempo de ejecución. NOTA: Noté que en /sys/shm/ existe el archivo renombrado, por lo que el cambio de nombre parece tener éxito.

    – Andrea Sprega

    14 de febrero de 2011 a las 16:25

  • shm_open("name") en Linux normalmente se traduce como open("/dev/shm/name"). Debería poder cambiarle el nombre como un archivo normal. Tenga en cuenta que “/dev/shm/” es el punto de montaje predeterminado de tmpfs en Linux. Se puede mapear en otro lugar. Ver google.com/codesearch/p?hl=en#xy1xtVWIKOQ/pub/glibc/releases/…

    – Máximo Egorushkin

    14 de febrero de 2011 a las 16:51

  • Gracias por la nota. ¿Tiene alguna idea de por qué el cambio de nombre podría causar un error de bus si intento acceder a la zona de memoria compartida?

    – Andrea Sprega

    14 de febrero de 2011 a las 16:54

  • Lo hace shm_open() resulta en SIGBUS?

    – Máximo Egorushkin

    14 de febrero de 2011 a las 16:59


  • /dev/shm o shm_open tiene una limitación de cuota predeterminada de la mitad del tamaño de la memoria física. Puede shm_open y mmap un espacio de memoria más grande inicialmente, pero cuando escribe más allá de la limitación o alguien más también usa /dev/shm o shm_open para que el espacio restante sea cero, su programa obtiene SIGBUS directamente.

    – jclin

    17/03/2016 a las 19:53

avatar de usuario
lotario

Solo para cualquiera que lea esta pregunta en 2018 y después. La solución ahora es usar memfd_create para crear un archivo anónimo y usar un socket Unix para pasar este identificador de archivo al otro proceso.

memfd_create es una llamada al sistema solo para Linux

  • … Y ya no es una llamada al sistema solo para Linux desde 2019porque FreeBSD ahora también lo tiene, aunque tenía acceso a una funcionalidad equivalente incluso antes porque FreeBSD le permite explícitamente ftruncate(2) y read(2) descriptores que obtuviste de shm_open(2). Linux en realidad lo tenía desde 3.17 en 2014, no desde 2018, aunque Glibc de hecho solo se dignó exponerlo en 2.27 en 2018. En OpenBSD ≥ 5.4 (2013), puede usar shm_mkstemp(2) en lugar de. Otra respuesta SO tiene los detalles.

    – Alex Shpilkin

    20 de febrero a las 21:55

  • @AlexShpilkin Genial, ahora esperemos que también lo tengamos en macOS. No estoy seguro de lo bueno que es Apple sincronizando Darwin con FreeBSD hoy en día

    – Lotario

    20 de febrero a las 23:37

Eso no va a funcionar.

Si crea una asignación después de la bifurcación (), no será lo mismo en los otros procesos relacionados.

No puede asumir el intercambio de punteros de esta manera.

Si realmente quiere hacerlo de esta manera (¡no lo recomendaría!), debe mapear un área grande antes de la bifurcación (), luego asignar de alguna manera, búferes de un tamaño adecuado (¡sin condiciones de carrera con otros procesos, por supuesto! ) y pasar esos punteros.

Dos procesos relacionados que llaman a mmap() después de una bifurcación, pueden recuperar el mismo puntero, apuntando a una memoria diferente. De hecho, esto es extremadamente probable.

¿Ha sido útil esta solución?

Esta web utiliza cookies propias y de terceros para su correcto funcionamiento y para fines analíticos y para mostrarte publicidad relacionada con sus preferencias en base a un perfil elaborado a partir de tus hábitos de navegación. Al hacer clic en el botón Aceptar, acepta el uso de estas tecnologías y el procesamiento de tus datos para estos propósitos. Configurar y más información
Privacidad