2012-09-05 9 views
6

Considere la siguiente aplicación: un servidor de búsqueda web que al inicio crea un gran índice en la memoria de páginas web basado en datos leídos del disco. Una vez inicializado, el índice en memoria no se puede modificar y se inician varios subprocesos para atender las consultas de los usuarios. Supongamos que el servidor está compilado con código nativo y utiliza subprocesos del sistema operativo.¿Es factible implementar primitivas de simultaneidad de concurrencia de Linux que proporcionen un mejor aislamiento que los hilos pero un rendimiento comparable?

Ahora, el modelo de subprocesamiento no ofrece aislamiento entre subprocesos. Un subproceso con errores o cualquier código que no sea seguro para subprocesos, puede dañar el índice o dañar la memoria asignada por y, lógicamente, pertenece a otro subproceso. Tales problemas son difíciles de detectar y depurar.

Teóricamente, Linux permite forzar un mejor aislamiento. Una vez que se inicializa el índice, la memoria que ocupa se puede marcar como de solo lectura. Los subprocesos se pueden reemplazar con procesos que comparten el índice (memoria compartida) pero, aparte de eso, tienen montones separados y no pueden dañarse entre sí. La operación ilegal es detectada automáticamente por el hardware y el sistema operativo. No se necesitan mutex u otras primitivas de sincronización. Las carreras de datos relacionadas con la memoria se eliminan por completo.

¿Es factible tal modelo en la práctica? ¿Conoce alguna aplicación de la vida real que haga tales cosas? ¿O tal vez hay algunas dificultades fundamentales que hacen que ese modelo no sea práctico? ¿Cree que este enfoque introduciría una sobrecarga de rendimiento en comparación con los hilos tradicionales? Teóricamente, la memoria que se utiliza es la misma, pero ¿hay algunos problemas relacionados con la implementación que harían las cosas más lentas?

+0

Ciertamente hay aplicaciones que usan mmap para marcar varios espacios de memoria como de solo lectura. Sin embargo, esto normalmente se debe a motivos de rendimiento y no a la protección contra el código defectuoso. – Gray

+0

Aunque ciertamente no quiero comenzar una guerra religiosa, cambiar al uso de un lenguaje (como Java) que admite tipos verdaderamente inmutables resolvería muchos de los problemas con "hilos defectuosos" que "corrompen la memoria". – Gray

+2

La corrupción de memoria en programas de subprocesos múltiples ocurre no solo cuando el hilo escribe en una ubicación aleatoria en la memoria (estos errores son relativamente fáciles de evitar y detectar) sino también cuando el hilo obtiene una referencia válida a un objeto que no es seguro para subprocesos utilizado por otro hilo. Dichos errores son mucho más difíciles de prevenir y detectar, y pueden ocurrir en cualquier programa de subprocesos múltiples, sin importar el idioma. –

Respuesta

4

La solución obvia es no utilizar ningún tipo de subprocesos. Usa procesos separados. Como cada proceso tiene mucho en común con el código y las estructuras de solo lectura, hacer que los datos de solo lectura sean compartidos es trivial: formatéelo según sea necesario para el uso en memoria dentro de un archivo y asigne el archivo a la memoria.

Usando este esquema, solo la variable por proceso de datos sería independiente. El código se compartiría y los datos inicializados estáticamente se compartirían hasta que se escriban. Si un proceso grazna, no hay impacto en otros procesos. No hay problemas de concurrencia en absoluto.

0

Creo que puede encontrar memcached interesante. Además, puede crear una memoria compartida y abrirla como de solo lectura y luego crear sus hilos. Esto no debería causar mucha degradación del rendimiento.

1

Puede usar mprotect() para hacer que su índice sea de solo lectura. En un sistema de 64 bits puedes mapear la memoria local para cada hilo en una dirección aleatoria (ver this Wikipedia article on address space randomization) que hace que las probabilidades de corrupción de memoria de un hilo toquen otro astronómicamente pequeño (y por supuesto cualquier corrupción que omita completamente la memoria mapeada causará una segfault). Obviamente, necesitarás tener diferentes montones para cada hilo.

+0

¿Pueden los subprocesos tener diferentes montones, o diferentes montículos distinguen subprocesos de procesos? –

+0

El montón está justo donde 'malloc' obtiene su memoria. Para dar a los diferentes hilos diferentes montones, solo se necesita sacar cada hilo de un grupo diferente (usando datos específicos de hilo).Solo necesita la biblioteca correcta de malloc con las opciones correctas. –

+0

El problema es que la idea de aleatorización del montón evitaría solo una clase de errores: corrupción de la memoria debido a escrituras en ubicaciones aleatorias. Como escribí en otro comentario, estos errores son relativamente más fáciles de prevenir y detectar. El problema más grande son las carreras de datos que el aislamiento total eliminaría por completo. Digamos que un hilo llama a una función que devuelve un puntero a un objeto estático no seguro para subprocesos. Si otro subproceso llama a la misma función, tiene una carrera de datos, y no ayuda que el puntero devuelto sea aleatorio. El puntero no se supuso que se obtuvo a través de una llamada válida. –

Cuestiones relacionadas