¿Por qué un mutex pthread se considera "más lento" que un futex?
linux pthreads (5)
Debido a que permanecen en el espacio de usuario tanto como sea posible, lo que significa que requieren menos llamadas al sistema, que es intrínsecamente más rápido porque el cambio de contexto entre el usuario y el modo kernel es costoso.
Supongo que estás hablando de hilos del kernel cuando hablas de los hilos POSIX. Es totalmente posible tener una implementación completamente en el espacio de usuario de los hilos POSIX que no requieren llamadas al sistema pero que tienen otros problemas propios.
Tengo entendido que un futex está a medio camino entre un hilo POSIX del kernel y un hilo POSIX del espacio de usuario.
¿Por qué los mutexes POSIX se consideran más pesados o más lentos que los futexes? ¿De dónde viene la sobrecarga en el tipo de pthread mutex? He oído que los subtítulos pthread se basan en futexes, y cuando no se han probado, no realices ninguna llamada al kernel. Parece entonces que un mutex pthread es simplemente un "envoltorio" alrededor de un futex.
¿Está la sobrecarga simplemente en la llamada a la función-envoltura y la necesidad de la función mutex para "configurar" el futex (es decir, básicamente la configuración de la pila para la llamada de función pthread mutex)? ¿O hay algunos pasos de barrera de memoria adicionales que tienen lugar con el pthread mutex?
En AMD64, un futex es de 4 bytes, mientras que un NPTL pthread_mutex_t es de 56 bytes. Sí, hay una sobrecarga significativa.
Futexes se crearon para mejorar el rendimiento de pthread mutexes. NPTL usa futexes, LinuxThreads futexes predatados, que creo que es donde viene la consideración "más lenta". Los mutexes NPTL pueden tener una sobrecarga adicional, pero no debería ser mucho.
Editar: La sobrecarga real básicamente consiste en:
- seleccionando el algoritmo correcto para el tipo mutex (normal, recursivo, adaptativo, comprobación de errores, normal, robusto, prioridad-herencia, prioridad protegida), donde el código insinúa al compilador que es probable que usemos un mutex normal (por lo tanto debe transmitir eso a la lógica de predicción de bifurcación de la CPU),
- y una escritura del propietario actual del mutex si logramos tomarlo, que normalmente debería ser rápido, ya que reside en la misma línea de caché que el bloqueo real que acabamos de tomar, a menos que el bloqueo esté fuertemente disputado y algún otro La CPU accedió al bloqueo entre el momento en que lo tomamos y el momento en que intentamos escribir al propietario (esta escritura no es necesaria para mutexes normales, pero es necesaria para la detección de errores y mutexes recursivos).
Por lo tanto, unos pocos ciclos (caso típico) a unos pocos ciclos + una predicción errónea de ramas + una falta de memoria caché adicional (en el peor de los casos).
La respuesta breve a su pregunta es que se sabe que los futexes se implementan de la manera más eficiente posible, mientras que un mutex pthread puede o no ser implementado. Como mínimo, un mutex pthread tiene una sobrecarga asociada con la determinación del tipo de mutex y los futex no. Así que un futex casi siempre será al menos tan eficiente como un mutex pthread, hasta que alguien cree una estructura más ligera que un futex y luego lanza una implementación pthreads que usa eso para su mutex predeterminado.
Técnicamente, los mutexes pthread no son más lentos o más rápidos que los futexes. pthread es solo una API estándar, así que si son lentos o rápidos depende de la implementación de esa API .
Específicamente en Linux los subtextos pthread se implementan como futexes y, por lo tanto, son rápidos. En realidad, no desea utilizar la API futex en sí misma, ya que es muy difícil de usar, no tiene las funciones de envoltura adecuadas en glibc y requiere codificación en ensamblaje que no sería portátil. Afortunadamente para nosotros, los mantenedores de glibc ya han codificado todo esto para nosotros bajo el capó de la API pthread mutex.
Ahora, debido a que la mayoría de los sistemas operativos no implementaron futexes , los programadores generalmente se refieren a pthread mutex es el rendimiento que se obtiene de la implementación habitual de pthread mutexes, que es, más lento.
Por lo tanto, es un hecho estadístico que en la mayoría de los sistemas operativos que cumplen con POSIX, pthread mutex se implementa en el espacio del núcleo y es más lento que un futex. En Linux tienen el mismo rendimiento. Podría ser que haya otros sistemas operativos donde pthread mutexes se implementan en el espacio de usuario (en el caso no identificado) y, por lo tanto, tienen un mejor rendimiento, pero en este momento solo conozco Linux.