linux - pthread - ¿Cuándo deberíamos usar mutex y cuándo deberíamos usar semáforo?
pthread mutex (11)
¿Cuándo deberíamos usar mutex y cuándo deberíamos usar semáforo?
¡Es muy importante entender que un mutex no es un semáforo con el conteo 1!
Esta es la razón por la que hay cosas como los semáforos binarios (que en realidad son semáforos con el recuento 1).
La diferencia entre un Mutex y un semáforo binario es el principio de propiedad:
Un mutex es adquirido por una tarea y, por lo tanto, también debe ser liberado por la misma tarea. Esto permite solucionar varios problemas con los semáforos binarios (publicación Accidental, interbloqueo recursivo e inversión de prioridad).
Advertencia: escribí "lo hace posible", si y cómo se solucionan estos problemas depende de la implementación del sistema operativo.
Como el mutex tiene que ser liberado por la misma tarea, no es muy bueno para la sincronización de tareas. Pero si se combina con variables de condición, se obtienen bloques de construcción muy poderosos para construir todo tipo de primitivas ipc.
Así que mi recomendación es: si tienes mutexes y variables de condición (como con POSIX pthreads) implementados, úsalos.
Use semáforos solo si se ajustan exactamente al problema que está tratando de resolver, no intente construir otras primitivas (por ejemplo, rw-locks fuera de semáforos, use mutexes y variables de condición para estos)
Hay muchos malentendidos y semáforos. La mejor explicación que encontré hasta ahora está en este artículo de 3 partes:
Mutex contra semáforos - Parte 1: semáforos
Mutex vs. Semáforos - Parte 2: El Mutex
Mutex contra semáforos - Parte 3 (parte final): Problemas de exclusión mutua
Así es como recuerdo cuándo usar qué:
Semáforo: use un semáforo cuando (hilo) quiera dormir hasta que otro hilo le indique que se despierte. El semáforo ''abajo'' ocurre en un subproceso (productor) y el semáforo ''arriba'' (para el mismo semáforo) ocurre en otro subproceso (consumidor) p. Ej .: en un problema productor-consumidor, el productor quiere dormir hasta que al menos un espacio intermedio esté vacío - solo el hilo de consumidor puede decir cuándo un espacio de búfer está vacío.
Mutex: utilice un mutex cuando (hilo) quiera ejecutar código que no debería ser ejecutado por ningún otro hilo al mismo tiempo. Mutex ''abajo'' ocurre en un hilo y mutex ''arriba'' debe suceder en el mismo hilo más adelante. Por ejemplo: si está eliminando un nodo de una lista global vinculada, no quiere que otro hilo se ensucie con punteros mientras está eliminando el nodo. Cuando adquiere un mutex y está ocupado eliminando un nodo, si otro hilo intenta adquirir el mismo mutex, se pondrá en modo suspensión hasta que libere el mutex.
Spinlock: usa un spinlock cuando realmente quieras usar un mutex, pero tu hilo no puede dormir. por ejemplo: un controlador de interrupción dentro del núcleo del sistema operativo nunca debe dormir. Si lo hace, el sistema se congelará / se bloqueará. Si necesita insertar un nodo en la lista de enlaces compartidos globalmente desde el manejador de interrupciones, adquiera un spinlock - insert node - release spinlock.
Como se señaló, un semáforo con un recuento de uno es lo mismo que un semáforo ''binario'' que es lo mismo que un mutex.
Las principales cosas que he visto en los semáforos con un recuento mayor al utilizado son las situaciones de productor / consumidor en las que tiene una cola de un cierto tamaño fijo.
Tienes dos semáforos entonces. El primer semáforo se establece inicialmente como el número de elementos en la cola y el segundo semáforo se establece en 0. El productor realiza una operación P en el primer semáforo y lo agrega a la cola. y hace una operación V en el segundo. El consumidor realiza una operación P en el segundo semáforo, elimina de la cola y luego realiza una operación V en la primera.
De esta forma, el productor se bloquea cada vez que llena la cola, y el consumidor se bloquea siempre que la cola esté vacía.
Consulte "The Toilet Example" - http://pheatt.emporia.edu/courses/2010/cs557f10/hand07/Mutex%20vs_%20Semaphore.htm :
Mutex:
Es la llave de un baño. Una persona puede tener la llave, ocupar el baño, en ese momento. Cuando termina, la persona da (libera) la llave a la siguiente persona en la cola.
Oficialmente: "Los mensajes mutex se utilizan generalmente para serializar el acceso a una sección de código de reentrada que no se puede ejecutar simultáneamente por más de un hilo. Un objeto mutex solo permite un hilo en una sección controlada, forzando a otros hilos que intentan obtener acceso a esa sección para esperar hasta que el primer hilo haya salido de esa sección ". Ref: Symbian Developer Library
(Un mutex es realmente un semáforo con valor 1.)
Semáforo:
Es la cantidad de llaves de inodoro idénticas gratuitas. Ejemplo, digamos que tenemos cuatro baños con cerraduras y llaves idénticas. El recuento de semáforos (el recuento de claves) se establece en 4 al principio (los cuatro retretes son gratuitos), luego el valor del recuento disminuye a medida que las personas ingresan. Si todos los retretes están llenos, es decir, no quedan claves libres, el recuento de semáforos es 0. Ahora, cuando eq. una persona deja el baño, el semáforo aumenta a 1 (una tecla libre) y se le da a la siguiente persona en la fila.
Oficialmente: "Un semáforo restringe el número de usuarios simultáneos de un recurso compartido hasta un número máximo. Los subprocesos pueden solicitar acceso al recurso (decrementando el semáforo) y pueden indicar que han terminado de usar el recurso (incrementando el semáforo). " Ref: Symbian Developer Library
Creo que la pregunta debería ser la diferencia entre mutex y semáforo binario.
Mutex = Es un mecanismo de bloqueo de propiedad, solo el hilo que adquiere el bloqueo puede liberar el bloqueo.
semáforo binario = Es más un mecanismo de señal, cualquier otro subproceso de mayor prioridad si se quiere puede señalar y tomar el bloqueo.
Mutex es para proteger el recurso compartido.
Semaphore es enviar los hilos.
Mutex:
Imagina que hay algunas entradas para vender. Podemos simular un caso en el que muchas personas compran los boletos al mismo tiempo: cada persona es un hilo para comprar boletos. Obviamente, necesitamos usar el mutex para proteger los tickets porque es el recurso compartido.
Semáforo:
Imagine que tenemos que hacer un cálculo de la siguiente manera:
c = a + b;
Además, necesitamos una función geta()
para calcular a
, una función getb()
para calcular b
y una función getc()
para hacer el cálculo c = a + b
.
Obviamente, no podemos hacer c = a + b
menos que se hayan terminado geta()
y getb()
.
Si las tres funciones son tres hilos, necesitamos enviar los tres hilos.
int a, b, c;
void geta()
{
a = calculatea();
semaphore_increase();
}
void getb()
{
b = calculateb();
semaphore_increase();
}
void getc()
{
semaphore_decrease();
semaphore_decrease();
c = a + b;
}
t1 = thread_create(geta);
t2 = thread_create(getb);
t3 = thread_create(getc);
thread_join(t3);
Con la ayuda del semáforo, el código anterior puede garantizar que t3
no hará su trabajo hasta que t1
y t2
hayan hecho su trabajo.
En una palabra, semáforo es para hacer que los hilos se ejecuten como un orden logicial mientras que mutex es para proteger el recurso compartido.
Por lo tanto, NO son lo mismo, incluso si algunas personas siempre dicen que mutex es un semáforo especial con el valor inicial 1. También puede decir esto, pero tenga en cuenta que se utilizan en diferentes casos. No reemplace uno por el otro incluso si puede hacer eso.
Si bien la respuesta de @opaxdiablo es totalmente correcta, me gustaría señalar que el escenario de uso de ambas cosas es bastante diferente. El mutex se usa para proteger partes del código que se ejecutan simultáneamente, los semáforos se usan para un hilo para señalar otro hilo para ejecutar.
/* Task 1 */
pthread_mutex_lock(mutex_thing);
// Safely use shared resource
pthread_mutex_unlock(mutex_thing);
/* Task 2 */
pthread_mutex_lock(mutex_thing);
// Safely use shared resource
pthread_mutex_lock(mutex_thing);
El escenario del semáforo es diferente:
/* Task 1 - Producer */
sema_post(&sem); // Send the signal
/* Task 2 - Consumer */
sema_wait(&sem); // Wait for signal
Ver http://www.netrino.com/node/202 para más explicaciones
Todas las respuestas anteriores son de buena calidad, pero esta solo es para memorizar. El nombre Mutex se deriva de Mutuamente Exclusivo, por lo tanto, estás motivado para pensar en un bloqueo mutex como exclusión mutua entre dos, como en uno solo a la vez, y si lo poseí, puedes tenerlo solo después de que lo libere. Por otro lado, tal caso no existe para Semaphore es como una señal de tráfico (que también significa la palabra semáforo).
Tratando de no sonar tonto, pero no puedo evitarlo.
Tu pregunta debería ser ¿cuál es la diferencia entre mutex y semáforos? Y para ser una pregunta más precisa debería ser, ''¿cuál es la relación entre mutex y semáforos?''
(Hubiera agregado esa pregunta, pero estoy cien por ciento seguro de que un moderador excesivamente entusiasta la cerraría como duplicado sin comprender la diferencia entre la diferencia y la relación).
En la terminología de objetos podemos observar que:
observation.1 Semaphore contiene mutex
observación.2 Mutex no es semáforo y el semáforo no es mutex.
Hay algunos semáforos que actuarán como si fueran mutex, llamados semáforos binarios, pero están volviendo loco NO mutex.
Hay un ingrediente especial llamado Signaling (posix usa condition_variable para ese nombre), requerido para hacer un semáforo fuera de mutex. Piense en ello como una fuente de notificación. Si dos o más subprocesos están suscritos a la misma fuente de notificación, entonces es posible enviarles un mensaje a UNA o TODO para que se active.
Podría haber uno o más contadores asociados con semáforos, que están protegidos por mutex. El escenario más simple para semáforo, hay un contador único que puede ser 0 o 1.
Aquí es donde la confusión se vierte en la lluvia del monzón.
Un semáforo con un contador que puede ser 0 o 1 NO es mutex.
Mutex tiene dos estados (0,1) y una propiedad (tarea). Semaphore tiene un mutex, algunos contadores y una variable de condición.
Ahora, use su imaginación, y cada combinación de uso de contador y cuándo señalizar puede hacer un tipo de semáforo.
Contador único con valor 0 o 1 y señalización cuando el valor va a 1 Y luego desbloquea a uno de los que esperan en la señal == Semáforo binario
Contador único con valor de 0 a N y señalización cuando el valor va a menos de N, y bloquea / espera cuando los valores son N == Contando el semáforo
Contador único con valor 0 a N y señalización cuando el valor va a N, y bloquea / espera cuando los valores son menores que N == Semáforo de barrera (bueno, si no lo llaman, entonces deberían).
Ahora a tu pregunta, cuándo usar qué. (O la versión bastante correcta de la pregunta.3 cuándo usar mutex y cuándo usar semáforo binario, ya que no hay comparación con el semáforo no binario.) Utilice mutex cuando 1. desee un comportamiento personalizado, que no sea proporcionado por binario semáforo, tales como spin-lock o fast-lock o recursive-locks. Generalmente puede personalizar mutexes con atributos, pero personalizar el semáforo no es más que escribir un nuevo semáforo. 2. quieres primitivo ligero o más rápido
Use semáforos, cuando lo que quiere es exactamente lo que proporciona.
Si no comprende lo que le proporciona su implementación de semáforo binario, en mi humilde opinión, use mutex.
Y, por último, lea un libro en lugar de confiar solo en SO.
Un mutex es un caso especial de un semáforo. Un semáforo permite que varios hilos entren en la sección crítica. Al crear un semáforo, usted define cómo se permiten los subprocesos en la sección crítica. Por supuesto, su código debe poder manejar varios accesos a esta sección crítica.
Un mutex es un objeto de exclusión mutua, similar a un semáforo pero que solo permite un casillero a la vez y cuyas restricciones de propiedad pueden ser más estrictas que un semáforo.
Se puede considerar como equivalente a un semáforo de conteo normal (con un recuento de uno) y el requisito de que solo se puede liberar con el mismo hilo que lo bloqueó (a) .
Un semáforo, por otro lado, tiene un conteo arbitrario y puede ser bloqueado por ese número de casilleros al mismo tiempo. Y puede no tener el requisito de que sea lanzado por el mismo hilo que lo reclamó (pero, de lo contrario, debe rastrear cuidadosamente quién es el responsable actual, al igual que la memoria asignada).
Entonces, si tiene varias instancias de un recurso (digamos tres unidades de cinta), podría usar un semáforo con un conteo de 3. Tenga en cuenta que esto no le dice cuál de esas unidades de cinta tiene, solo que tiene un cierto número.
También con semáforos, es posible que un solo casillero bloquee varias instancias de un recurso, como una copia de cinta a cinta. Si tiene un recurso (digamos una ubicación de memoria que no desea dañar), un mutex es más adecuado.
Las operaciones equivalentes son:
Counting semaphore Mutual exclusion semaphore
-------------------------- --------------------------
Claim/decrease (P) Lock
Release/increase (V) Unlock
Aparte: en caso de que alguna vez se haya preguntado por las extrañas letras utilizadas para reclamar y liberar semáforos, es porque el inventor era holandés. Probeer te verlagen significa intentar disminuir mientras que verhogen significa aumentar.
(a) ... o puede considerarse como algo totalmente distinto de un semáforo, que puede ser más seguro dados sus usos casi siempre diferentes.