En qué situación se utiliza un semáforo sobre un mutex en C++?


A través de los recursos que he leído sobre multithreading, mutex se usa y discute más a menudo en comparación con un semáforo. Mi pregunta es ¿cuándo se usa un semáforo sobre un mutex? No veo semáforos en el hilo Boost. ¿Significa eso que los semáforos ya no se usan mucho en estos días?

Por lo que tengo entendido, los semáforos permiten que un recurso sea compartido por varios hilos. Esto solo es posible si esos hilos solo están leyendo el recurso pero no escribiendo. ¿Es correcto?

Author: jasonline, 2010-02-28

9 answers

Aumentar.El hilo tiene mutexes y variables de condición. Puramente en términos de funcionalidad, los semáforos son por lo tanto redundantes[*], aunque no se si es por eso que se omiten.

Los semáforos son primitivos más básicos, más simples, y posiblemente implementados para ser más rápidos, pero no tienen prioridad: evitar la inversión. Podría decirse que son más difíciles de usar que las variables de condición, porque requieren el código del cliente para garantizar que el número de publicaciones "coincida" con el número de esperas en algunos de manera apropiada. Con las variables de condición es fácil tolerar mensajes falsos, porque nadie realmente hace nada sin verificar la condición.

Read vs.write resources es una red herring IMO, no tiene nada que ver con la diferencia entre un mutex y un semáforo. Si usa un semáforo de conteo, podría tener una situación en la que múltiples subprocesos accedan simultáneamente al mismo recurso, en cuyo caso presumiblemente tendría que ser acceso de solo lectura. En eso situación, es posible que pueda utilizar shared_mutex desde Boost.Hilo en su lugar. Pero los semáforos no son "para" proteger los recursos de la forma en que lo son los mutexes, son "para" enviar una señal de un hilo a otro. Es posible usarlas para controlar el acceso a un recurso.

Eso no significa que todos los usos de semáforos deban relacionarse con recursos de solo lectura. Por ejemplo, puede usar un semáforo binario para proteger un recurso de lectura / escritura. Sin embargo, podría no ser una buena idea, ya que un mutex a menudo le da un mejor comportamiento de programación.

[*] Así es como se implementa un semáforo de conteo usando un mutex y una variable de condición. Para implementar un semáforo compartido, por supuesto, necesita un mutex/condvar compartido:

struct sem {
    mutex m;
    condvar cv;
    unsigned int count;
};

sem_init(s, value)
    mutex_init(s.m);
    condvar_init(s.cv);
    count = value;

sem_wait(s)
    mutex_lock(s.m);
    while (s.count <= 0) {
        condvar_wait(s.cv, s.m);
    }
    --s.count;
    mutex_unlock(s.m);

sem_post(s)
    mutex_lock(s.m);
    ++s.count;
    condvar_broadcast(s.cv)
    mutex_unlock(s.m);

Por lo tanto, todo lo que se puede hacer con semáforos, se puede hacer con mutexes y variables de condición. Sin embargo, no necesariamente implementando un semáforo.

 4
Author: Steve Jessop,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-03-01 10:35:46

El caso de uso típico para un mutex (permitiendo solo un acceso de hilo a un recurso en cualquier momento) es mucho más común que los usos típicos si un semáforo. Pero un semáforo es en realidad el concepto más general: Un mutex es (casi) un caso especial de un semáforo.

Las aplicaciones típicas serían: No desea crear más de (por ejemplo) 5 conexiones de base de datos. No importa cuántos hilos de trabajo haya, tienen que compartir estas 5 conexiones. O, si se ejecuta en una máquina N-core, es posible que desee asegurarse de que ciertas tareas intensivas en CPU / memoria no se ejecuten en más de N subprocesos al mismo tiempo (porque eso solo reduciría el rendimiento debido a los cambios de contexto y los efectos de thrashing de caché). Es posible que incluso desee limitar el número de tareas intensivas de CPU/memoria en paralelo a N-1, para que el resto del sistema no muera de hambre. O imagine que una tarea determinada necesita mucha memoria, por lo que ejecutar más de N instancias de esa tarea al mismo tiempo llevaría a la paginación. Podrías usar un semáforo aquí, para asegurarse de que no más de N instancias de esta tarea particular se ejecutan al mismo tiempo.

EDIT/PS: De tu pregunta "Esto solo es posible si esos hilos solo están leyendo el recurso pero no escribiendo. ¿Es correcto?"y tu comentario, me parece como si estuvieras pensando en un recurso como una variable o un flujo, que se puede leer o escribir y que solo se puede escribir por un hilo a la vez. No. Esto es engañoso en este contexto.

Piensa en recursos como "agua". Puedes usar agua para lavar los platos. Puedo usar agua para lavar mis platos al mismo tiempo. No necesitamos ningún tipo de sincronización para eso, porque hay suficiente agua para los dos. No necesariamente usamos la misma agua. (Y no puedes "leer" o "escribir" agua.) Pero la cantidad total de agua es finita. Así que no es posible que cualquier número de partes para lavar sus platos al mismo tiempo. Este tipo de sincronización se realiza con un semáforo. Solo que generalmente no con agua, sino con otros recursos finitos como memoria, espacio en disco, rendimiento de IO o núcleos de CPU.

 18
Author: Niki,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-02-28 09:38:57

La esencia de la diferencia entre un mutex y un semáforo tiene que ver con el concepto de propiedad. Cuando se toma un mutex, pensamos en ese hilo como propietario del mutex y ese mismo hilo debe liberar más tarde el mutex de nuevo para liberar el recurso.

Para un semáforo, piense en tomar el semáforo como consumir el recurso, pero no realmente tomar posesión de él. Esto se conoce generalmente como el semáforo "vacío" en lugar de ser propiedad de un hilo. La característica de la semáforo es entonces que un hilo diferente puede " llenar "el semáforo de nuevo al estado" completo".

Por lo tanto, los mutexes se usan generalmente para la protección de concurrencia de recursos (es decir, EXlusion mutua) mientras que los semáforos se usan para la señalización entre hilos (como las banderas de semáforos que señalan entre naves). Un mutex por sí mismo realmente no puede ser utilizado para la señalización, pero los semáforos sí. Por lo tanto, la selección de uno sobre el otro depende de lo que está tratando de hacer.

Ver otra una de mis respuestas aquí para más discusión sobre un tema relacionado que cubre la distinción entre mutexes recursivos y no recursivos.

 11
Author: Tall Jeff,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-05-23 12:31:52

Para controlar el acceso a un número limitado de recursos compartidos por múltiples subprocesos (ya sea entre procesos o dentro de ellos).

En nuestra aplicación, teníamos un recurso muy pesado y que no queríamos asignar uno para cada uno de los hilos de trabajo M. Dado que un hilo de trabajo necesitaba el recurso para una pequeña parte de su trabajo, rara vez estábamos utilizando más de un par de los recursos simultáneamente.

Entonces, asignamos N de esos recursos y los pusimos detrás de un semáforo inicializado a N. Cuando más de N hilos intentaban usar el recurso, simplemente se bloqueaban hasta que uno estuviera disponible.

 9
Author: R Samuel Klatchko,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-02-28 16:13:56

Siento que no hay una manera simple de REALMENTE responder a su pregunta sin ignorar alguna información importante sobre los semáforos. La gente ha escrito muchos libros sobre semáforos , por lo que cualquier respuesta de uno o dos párrafos es un flaco favor. Un libro popular es El Pequeño Libro de Semáforos ... para aquellos que no les gustan los libros grandes :).

Aquí hay un decente largo artículo que entra en muchos de los detalles sobre cómo se utilizan los semáforos y cómo son destinado a ser utilizado.

Actualización:
Dan señaló algunos errores en mis ejemplos, lo dejaré con las referencias que ofrecen explicaciones mucho mejores que las mías :).

Aquí están las referencias que muestran las formas CORRECTAS en que uno debe usar un semáforo:
1. Artículo de IBM
2. Conferencia de Clase de la Universidad de Chicago
3. El artículo de Netrino que publiqué originalmente.
4. El papel "vender entradas" + código.

 3
Author: Kiril,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-02-28 18:58:34

Tomado de este artículo :

Un mutex permite la sincronización entre procesos. Si crea una instancia de un mutex con un nombre (como en el código anterior), el mutex se convierte en todo el sistema. Esto es realmente útil si está compartiendo la misma biblioteca entre muchas aplicaciones diferentes y necesita bloquear el acceso a una sección crítica de código que está accediendo a recursos que no se pueden compartir.

Finalmente, la clase Semáforo. Digamos que tienes un método que es realmente CPU intensivo, y también hace uso de los recursos que necesita para controlar el acceso a (usando Mutexes :)). También ha determinado que un máximo de cinco llamadas al método es sobre todo lo que su máquina puede hanlde sin hacer que no responda. Su mejor solución aquí es hacer uso de la clase Semaphore que le permite limitar un cierto número de subprocesos de acceso a un recurso.

 1
Author: Kane,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-02-28 10:40:54

Por lo que entiendo semáforos es un término fuertemente relacionado con la CIP en estos días. Todavía significa variable protegida muchos procesos pueden modificar, pero entre los procesos y esta característica es compatible con el sistema operativo.

Por lo general, no necesitamos una variable y un simple mutex cubre todos nuestros requisitos. Si todavía necesitamos una variable, probablemente, programamos nosotros mismos - "variable + mutex" para obtener más control.

Resume: no usamos semáforos en multihilo porque usualmente usamos mutex para simplificar y control, y usamos semáforos para IPC porque es compatible con el sistema operativo y un nombre oficial para el mecanismo de sincronización de procesos.

 0
Author: seas,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-02-28 09:28:49

Los semáforos fueron concebidos originalmente para la sincronización entre procesos. Windows usa WaitForMultipleObjects que es como un semáforo. En el mundo de Linux, la implementación inicial de pthread no permitía que un mutex se compartiera a través del proceso. Ahora lo hacen. El concepto de romper el incremento atómico (incremento entrelazado en Windows) junto con el ligero mutex es la implementación más práctica en estos días después de que los hilos se convirtieran en la unidad de programación para la cpu. Si el incremento y el bloqueo estamos juntos (semáforo), el tiempo para adquirir / liberar bloqueos será demasiado largo y no podemos dividir esas 2 funciones de la unidad como lo hacemos hoy para el rendimiento y mejores construcciones de sincronización.

 0
Author: MRN,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-01-20 17:22:35

De lo que aprendí sobre semáforos y mutex en la universidad, los semáforos son objetos más teóricos, mientras que los mutex son una implementación de semáforos. Teniendo esto en cuenta, los semáforos son más flexibles.

Los Mutex son altamente dependientes de la implementación. Se han optimizado para su propósito de bloqueo binario. El caso de uso normal de un mutex es un semáforo binario.

En general, cuando se intenta escribir código multiproceso libre de errores, la simplicidad ayuda. Objeto Mutex se usan más porque su simplicidad ayuda a evitar complejos escenarios de punto muerto que surgen del uso de semáforos.

 -1
Author: Kousha,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-02-28 10:51:44