Al usar la memoria compartida, cada proceso puede mapear la región compartida en un área diferente de su espacio de direcciones respectivo. Esto significa que cuando almacena punteros dentro de la región compartida, necesita store them as offsets del inicio de la región compartida. Desafortunadamente, esto complica el uso de las instrucciones atómicas (por ejemplo, si está intentando escribir un lock free algorithm). Por ejemplo, supongamos que tiene un grupo de nodos de referencia contados en la memoria compartida, creados por un solo escritor. El autor periódicamente actualiza atómicamente un puntero 'p' para apuntar a un nodo válido con recuento de referencia positivo. Los lectores quieren escribir atómicamente a 'p' porque apunta al comienzo de un nodo (una estructura) cuyo primer elemento es un recuento de referencia. Como p siempre apunta a un nodo válido, incrementar el recuento de ref es seguro, y hace que sea seguro quitar la referencia 'p' y acceder a otros miembros. Sin embargo, todo esto solo funciona cuando todo está en el mismo espacio de direcciones. Si los nodos y el puntero 'p' se almacenan en la memoria compartida, los clientes sufren una condición de carrera:¿Es posible almacenar punteros en la memoria compartida sin utilizar desplazamientos?
- x = leer p
- y = x + compensado
- refcount Incremento en y
Durante el paso 2, p puede cambiar y x ya no apunta a un nodo válido. La única solución que se me ocurre es obligar de algún modo a todos los procesos a ponerse de acuerdo sobre dónde asignar la memoria compartida, de modo que puedan almacenarse punteros reales en lugar de desplazamientos en la región mmap'd. ¿Hay alguna forma de hacer eso? Veo MAP_FIXED en la documentación de mmap, pero no sé cómo podría elegir una dirección segura.
Editar: Usando el ensamblaje en línea y el prefijo 'candado' en x86 tal vez sea posible construir un "incremento ptr X con desplazamiento Y por valor Z"? Opciones equivalentes en otras arquitecturas? No he escrito mucho montaje, no sé si existen las instrucciones necesarias.
Si cmpxchg ya hace una lectura atómica y escritura atómica, ¿es necesario el 'bloqueo'? ¿O eso asegura que el edi + edx se hace atómicamente? Solo he usado el ensamblaje MIPS. –
La cerradura garantiza el acceso atómico al bus de memoria por lo que es necesaria la instrucción de bloqueo. Probablemente también pueda usar API InterlockedCompareExchange (consulte MSDN para obtener una explicación). Al principio, carga el puntero de memoria de 32 bits como OldValue y luego increméntalo para obtener NewValue, luego de eso intenta hacer InterlockedCompareExchange. InterlockedCompareExchange (Destination + Offset, NewValue, OldValue) devolverá el valor comparado si no es igual a OldValue que otro hilo es intercambiarlo, por lo que no se realizó ningún cambio y debe repetir el procedimiento. –