pthread_create - pthreads php
¿Qué es PTHREAD_MUTEX_ADAPTIVE_NP? (3)
El símbolo se menciona allí:
http://elias.rhi.hi.is/libc/Mutexes.html
"LinuxThreads admite solo un atributo de exclusión mutua: el tipo de exclusión mutua, que es PTHREAD_MUTEX_ADUTTIVO_ADAPTIVO_NP para las mutexiones" rápidas ", PTHREAD_MUTEX_RECURSIVE_Agn. Esta es una extensión no portátil del estándar POSIX y no debe emplearse en programas portátiles.
El tipo de exclusión mutua determina qué sucede si un hilo intenta bloquear una exclusión mutua que ya posee con pthread_mutex_lock. Si el mutex es del tipo "rápido", pthread_mutex_lock simplemente suspende el hilo de llamada para siempre. Si el mutex es del tipo "comprobación de errores", pthread_mutex_lock regresa inmediatamente con el código de error EDEADLK. Si el mutex es del tipo "recursivo", la llamada a pthread_mutex_lock regresa inmediatamente con un código de retorno exitoso. El número de veces que el hilo que posee el mutex lo ha bloqueado se registra en el mutex. El hilo propietario debe llamar a pthread_mutex_unlock el mismo número de veces antes de que el mutex vuelva al estado desbloqueado.
El tipo de exclusión mutua predeterminado es "cronometrado", es decir, PTHREAD_MUTEX_TIMED_NP ".
EDITAR: actualizado con la información encontrada por jthill (gracias!)
Un poco más de información sobre las banderas de exclusión mutua y el PTHREAD_MUTEX_ADAPTIVE_NP se puede encontrar aquí :
"El PTHRED_MUTEX_ADAPTIVE_NP es un nuevo mutex destinado a un alto rendimiento en el sacrificio de la equidad e incluso los ciclos de la CPU. Este mutex no transfiere la propiedad a un hilo en espera, sino que permite la competencia. Además, en un núcleo SMP, la operación de bloqueo utiliza el hilado para volver a intentar el bloqueo para evitar el costo de la descodificación inmediata ".
Lo que básicamente sugiere lo siguiente: en caso de que sea deseable un alto rendimiento, tal mutex puede implementarse requiriendo consideraciones adicionales de la lógica del hilo debido a su naturaleza. Tendrá que diseñar un algoritmo que pueda usar estas propiedades para obtener un alto rendimiento. Algo que la carga se equilibra desde dentro (en lugar de "desde el kernel") donde el orden de ejecución no es importante.
Había un libro muy bueno para la programación multihilo linux / unix cuyo nombre se me escapa. Si lo encuentro lo actualizaré.
¿Dónde puedo encontrar documentación para mutexes pthread "adaptables"? El símbolo PTHREAD_MUTEX_ADAPTIVE_NP está definido en mi sistema, pero la única documentación que puedo encontrar en línea no dice nada acerca de qué es un mutex adaptativo o cuándo es apropiado usarlo.
Entonces ... ¿qué es y cuándo debo usarlo?
Para referencia, mi versión de libc es:
GNU C Library (Ubuntu EGLIBC 2.15-0ubuntu10.5) stable release version 2.15, by Roland McGrath et al.
Copyright (C) 2012 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.
There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A
PARTICULAR PURPOSE.
Compiled by GNU CC version 4.6.3.
Compiled on a Linux 3.2.50 system on 2013-09-30.
Available extensions:
crypt add-on version 2.1 by Michael Glad and others
GNU Libidn by Simon Josefsson
Native POSIX Threads Library by Ulrich Drepper et al
BIND-8.2.3-T5B
libc ABIs: UNIQUE IFUNC
For bug reporting instructions, please see:
<http://www.debian.org/Bugs/>.
y "uname -a" da
Linux desktop 3.2.0-55-generic #85-Ubuntu SMP Wed Oct 2 12:29:27 UTC 2013 x86_64 x86_64 x86_64 GNU/Linux
Aquí tienes Mientras lo leo, es un mutex brutalmente simple que no se preocupa por nada, excepto por hacer que el caso de no contienda se ejecute rápidamente.
PTHREAD_MUTEX_ADAPTIVE_NP
es algo que inventé mientras trabajaba en el papel de un colaborador de glibc para hacer que LinuxThreads sea más confiable y tenga un mejor desempeño. LinuxThreads fue el predecesor de la biblioteca NPTL de glibc, originalmente desarrollada como una biblioteca independiente por Xavier Leroy, quien también es conocido como uno de los creadores de OCaml .
El mutex adaptativo sobrevivió en NTPL en una forma esencialmente no modificada: el código es casi idéntico, incluidas las constantes mágicas para el suavizador del estimador y el giro máximo en relación con el estimador.
En SMP, cuando va a adquirir un mutex y ve que está bloqueado, puede ser subóptimo simplemente rendirse y llamar al kernel para bloquear. Si el propietario de la cerradura solo mantiene la cerradura durante unas pocas instrucciones, es más barato esperar la ejecución de esas instrucciones y luego adquirir la cerradura con una operación atómica, en lugar de gastar cientos de ciclos adicionales haciendo una llamada al sistema .
Los desarrolladores del kernel lo saben muy bien, lo cual es una de las razones por las que tenemos spinlocks en el kernel de Linux para secciones críticas rápidas. (Entre las otras razones está, por supuesto, ese código que no puede dormir, porque está en un contexto de interrupción, puede adquirir spinlocks).
La pregunta es, ¿cuánto tiempo debe esperar? Si gira para siempre hasta que se adquiere el bloqueo, eso puede ser sub-óptimo. Los programas de espacio de usuario no están bien escritos como el código del kernel (tos). Podrían tener largas secciones críticas. Tampoco pueden desactivar la prevención; a veces las secciones críticas explotan debido a un cambio de contexto. (Los subprocesos POSIX ahora brindan herramientas en tiempo real para solucionar esto: puede colocar los subprocesos en una prioridad en tiempo real y en la programación FIFO, y configurar la afinidad del procesador).
Creo que experimentamos con recuentos de iteraciones fijas, pero luego tuve esta idea: por qué deberíamos adivinar cuándo podemos medir. ¿Por qué no implementamos un estimador suavizado de la duración del bloqueo, de manera similar a lo que hacemos para el estimador de tiempo de espera de retransmisión de TCP (RTO). Cada vez que giramos en un candado, debemos medir cuántos giros se necesitaron para adquirirlo. Además, no debemos girar para siempre: quizás deberíamos girar solo a lo sumo el doble del valor actual del estimador. Cuando tomamos una medida, podemos suavizarla exponencialmente, en tan solo unas pocas instrucciones: tomar una fracción del valor anterior y del nuevo valor, y sumarlos, lo que equivale a agregar una fracción de su diferencia al reverso para el estimador: digamos, estimator += (new_val - estimator)/8
para una combinación de 1/8 a 7/8 entre el valor antiguo y el nuevo.
Puedes pensar en esto como un perro guardián. Supongamos que el estimador le dice que el bloqueo, en promedio, toma 80 giros para adquirir. Puede estar bastante seguro, entonces, que si ha ejecutado 160 giros, entonces algo está mal: el propietario del bloqueo está ejecutando un caso excepcionalmente largo, o tal vez ha tenido un error de página o se ha adelantado. En este punto, el hilo en espera corta sus pérdidas y llama al núcleo para bloquear.
Sin la medición, no puede hacer esto con precisión: no hay un valor de "talla única". Por ejemplo, un límite fijo de 200 giros sería subóptimo en un programa cuyas secciones críticas son tan cortas que casi siempre se puede buscar un bloqueo después de esperar solo 10 giros. La función de bloqueo mutex quemaría 200 iteraciones cada vez que se produce un tiempo de espera anómalo, en lugar de rendirse agradablemente en, por ejemplo, 20 ciclos de ahorro.
Este enfoque adaptativo es especializado, en el sentido de que no funcionará para todos los bloqueos en todos los programas, por lo que está empaquetado como un tipo de exclusión mutua especial. Por ejemplo, no funcionará muy bien para los programas que bloquean las exclusión mutuas durante períodos prolongados: períodos tan largos que se pierde más tiempo de CPU en los valores del estimador grande de lo que hubiera sido al ingresar al kernel. El enfoque tampoco es adecuado para uniprocesadores: todas las hebras, además de la que está intentando obtener el bloqueo, están suspendidas en el núcleo. El enfoque tampoco es adecuado en situaciones en las que la imparcialidad es importante: es un bloqueo oportunista. No importa cuántos otros hilos hayan estado esperando, sin importar cuánto tiempo, o cuál sea su prioridad, un nuevo hilo puede aparecer y arrebatar el bloqueo.
Si tiene un código de muy buen comportamiento con secciones críticas cortas que son altamente contendientes, y está buscando un mejor rendimiento en el SMP, vale la pena probar el mutex adaptativo.