Pregunta

En mis días como programador de BeOS, leí este artículo de Benoit Schillings, que describe cómo crear un" benaphore ": un método para usar una variable atómica para hacer cumplir una sección crítica que evita la necesidad de adquirir / liberar un mutex en común (no- contención) caso.

Pensé que era bastante inteligente, y parece que podrías hacer el mismo truco en cualquier plataforma que admita incremento / decremento atómico.

Por otro lado, esto parece algo que podría incluirse fácilmente en la implementación estándar de mutex en sí mismo ... en cuyo caso la implementación de esta lógica en mi programa sería redundante y no proporcionaría ningún beneficio.

¿Alguien sabe si las API de bloqueo modernas (por ejemplo, pthread_mutex_lock () / pthread_mutex_unlock ()) usan este truco internamente? Y si no, ¿por qué no?

¿Fue útil?

Solución

Lo que describe su artículo es de uso común hoy en día. Muy a menudo se llama " Sección crítica " ;, y consiste en una variable entrelazada, un grupo de banderas y un objeto de sincronización interna (Mutex, si no recuerdo mal). Generalmente, en los escenarios con poca contención, la Sección Crítica se ejecuta completamente en modo de usuario, sin involucrar el objeto de sincronización del núcleo. Esto garantiza una ejecución rápida. Cuando la contención es alta, el objeto kernel se usa para esperar, lo que libera el intervalo de tiempo conductor para un tiempo de respuesta más rápido.

Generalmente, tiene muy poco sentido implementar primitivas de sincronización en la actualidad. Los sistemas operativos vienen con una gran variedad de tales objetos, y están optimizados y probados en una gama de escenarios significativamente más amplia de lo que un único programador puede imaginar. Literalmente lleva años inventar, implementar y probar un buen mecanismo de sincronización. Eso no quiere decir que no tenga valor intentarlo :)

Otros consejos

Java AbstractQueuedSynchronizer (y su hermano AbstractQueuedLongSynchronizer ) funciona de manera similar, o al menos podría implementarse de manera similar. Estos tipos forman la base de varias primitivas de concurrencia en la biblioteca de Java, como ReentrantLock y FutureTask .

Funciona mediante el uso de un entero atómico para representar el estado. Un bloqueo puede definir el valor 0 como desbloqueado y 1 como bloqueado. Cualquier subproceso que desee adquirir el bloqueo intenta cambiar el estado de bloqueo de 0 a 1 mediante una operación atómica comparar y establecer ; Si el intento falla, el estado actual no es 0, lo que significa que el bloqueo es propiedad de algún otro hilo.

AbstractQueuedSynchronizer también facilita la espera en bloqueos y la notificación de condiciones al mantener colas CLH , que son listas enlazadas sin bloqueo que representan la línea de subprocesos que esperan adquirir el bloqueo o recibir una notificación a través de una condición. Dicha notificación mueve uno o todos los subprocesos que esperan en la condición a la cabeza de la cola de aquellos que esperan adquirir el bloqueo relacionado.

La mayoría de esta maquinaria se puede implementar en términos de un número entero atómico que representa el estado, así como un par de punteros atómicos para cada cola de espera. La programación real de los hilos que competirán para inspeccionar y cambiar la variable de estado (a través de, digamos, AbstractQueuedSynchronizer # tryAcquire (int) ) está fuera del alcance de dicha biblioteca y cae en el sistema host planificador.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top