Quando devemos usar mutex e quando devemos usar semáforo?
Quando devemos usar mutex e quando devemos usar semáforo?
Respostas:
Aqui está como eu me lembro quando usar o que -
Semáforo: Use um semáforo quando você (thread) quiser dormir até que outro thread diga para você acordar. O semáforo 'para baixo' acontece em um segmento (produtor) e o semáforo 'para cima' (para o mesmo semáforo) acontece em outro segmento (consumidor), por exemplo: No problema produtor-consumidor, o produtor deseja dormir até que pelo menos um slot de buffer esteja vazio - apenas o encadeamento do consumidor pode dizer quando um slot de buffer está vazio.
Mutex: Use um mutex quando você (thread) deseja executar código que não deve ser executado por qualquer outro thread ao mesmo tempo. Mutex 'down' acontece em um thread e mutex 'up' deve acontecer no mesmo thread posteriormente. por exemplo: Se você está excluindo um nó de uma lista global vinculada, você não quer que outro thread se misture com ponteiros enquanto você está excluindo o nó. Quando você adquire um mutex e está ocupado excluindo um nó, se outro thread tentar adquirir o mesmo mutex, ele será colocado no modo de espera até que você libere o mutex.
Spinlock: Use um spinlock quando você realmente quiser usar um mutex, mas seu thread não pode dormir. por exemplo: Um manipulador de interrupção no kernel do sistema operacional nunca deve dormir. Se isso acontecer, o sistema irá travar / travar. Se você precisar inserir um nó na lista vinculada compartilhada globalmente do manipulador de interrupção, adquira um spinlock - insira o nó - libere o spinlock.
Um mutex é um objeto de exclusão mútua, semelhante a um semáforo, mas que permite apenas um armário por vez e cujas restrições de propriedade podem ser mais rigorosas do que um semáforo.
Ele pode ser considerado equivalente a um semáforo de contagem normal (com uma contagem de um) e o requisito de que só pode ser liberado pelo mesmo thread que o bloqueou (a) .
Um semáforo, por outro lado, tem uma contagem arbitrária e pode ser bloqueado por tantos armários simultaneamente. E pode não ter um requisito de que seja lançado pelo mesmo thread que o reivindicou (mas, se não, você deve controlar cuidadosamente quem atualmente é responsável por ele, assim como a memória alocada).
Então, se você tiver várias instâncias de um recurso (digamos, três unidades de fita), você pode usar um semáforo com uma contagem de 3. Observe que isso não diz qual dessas unidades de fita você tem, apenas que você tem um certo número.
Também com semáforos, é possível que um único armário bloqueie várias instâncias de um recurso, como para uma cópia de fita para fita. Se você tiver um recurso (digamos, um local de memória que não deseja corromper), um mutex é mais adequado.
As operações equivalentes são:
Counting semaphore Mutual exclusion semaphore
-------------------------- --------------------------
Claim/decrease (P) Lock
Release/increase (V) Unlock
À parte: caso você já tenha se perguntado sobre as letras bizarras usadas para reivindicar e liberar semáforos, é porque o inventor era holandês. Probeer te verlagen significa tentar diminuir enquanto verhogen significa aumentar.
(a) ... ou pode ser pensado como algo totalmente distinto de um semáforo, que pode ser mais seguro devido aos seus usos quase sempre diferentes.
É muito importante entender que um mutex não é um semáforo com contagem 1!
Esta é a razão pela qual existem coisas como semáforos binários (que são realmente semáforos com contagem 1).
A diferença entre um Mutex e um Semáforo Binário é o princípio de propriedade:
Um mutex é adquirido por uma tarefa e, portanto, também deve ser liberado pela mesma tarefa. Isso torna possível corrigir vários problemas com semáforos binários (liberação acidental, deadlock recursivo e inversão de prioridade).
Advertência: eu escrevi "torna isso possível", se e como esses problemas são corrigidos depende da implementação do sistema operacional.
Como o mutex deve ser liberado pela mesma tarefa, não é muito bom para sincronização de tarefas. Mas, se combinado com variáveis de condição, você obtém blocos de construção muito poderosos para construir todos os tipos de primitivas ipc.
Portanto, minha recomendação é: se você implementou mutexes e variáveis de condição de forma limpa (como com POSIX pthreads), use-os.
Use semáforos apenas se eles se ajustarem exatamente ao problema que você está tentando resolver, não tente construir outras primitivas (por exemplo, rw-locks de semáforos, use mutexes e variáveis de condição para eles)
Há muitos mutexes e semáforos mal-entendidos. A melhor explicação que encontrei até agora está neste artigo de 3 partes:
Mutex vs. Semáforos - Parte 1: Semáforos
Mutex vs. Semáforos - Parte 2: O Mutex
Mutex vs. semáforos - Parte 3 (parte final): Problemas de exclusão mútua
Embora a resposta de @opaxdiablo seja totalmente correta, gostaria de salientar que o cenário de uso de ambas as coisas é bastante diferente. O mutex é usado para proteger partes do código contra execução simultânea, semáforos são usados para uma thread para sinalizar a execução de outra thread.
/* 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_unlock(mutex_thing); // unlock mutex
O cenário do semáforo é diferente:
/* Task 1 - Producer */
sema_post(&sem); // Send the signal
/* Task 2 - Consumer */
sema_wait(&sem); // Wait for signal
Consulte http://www.netrino.com/node/202 para mais explicações
sema_wait
:-) na minha opinião, eles são tanto sobre os recursos ea notificação entregue a outros tópicos é um efeito colateral (muito importante, em termos de performance) do proteção.
You say that the usage pattern of semaphores is to notify threads
Um ponto sobre a notificação de tópicos. Você pode chamar sem_post
de um manipulador de sinal com segurança ( pubs.opengroup.org/onlinepubs/009695399/functions/… ), mas não é recomendado chamar pthread_mutex_lock
e pthread_mutex_unlock
de manipuladores de sinal ( manpages.ubuntu.com/manpages/lucid/man3/… )
Consulte "O exemplo do banheiro" - http://pheatt.emporia.edu/courses/2010/cs557f10/hand07/Mutex%20vs_%20Semaphore.htm :
Mutex:
É a chave de um banheiro. Uma pessoa pode ficar com a chave - ocupar o banheiro - no momento. Ao terminar, a pessoa dá (libera) a chave para a próxima pessoa na fila.
Oficialmente: "Mutexes são normalmente usados para serializar o acesso a uma seção do código reentrante que não pode ser executado simultaneamente por mais de um thread. Um objeto mutex permite apenas um thread em uma seção controlada, forçando outros threads que tentam obter acesso a essa seção para esperar até que o primeiro segmento tenha saído dessa seção. " Ref: Symbian Developer Library
(Um mutex é na verdade um semáforo com valor 1.)
Semáforo:
É o número de chaves de banheiro idênticas gratuitas. Por exemplo, digamos que temos quatro banheiros com fechaduras e chaves idênticas. A contagem do semáforo - a contagem de chaves - é definida como 4 no início (todos os quatro banheiros são gratuitos), então o valor da contagem diminui conforme as pessoas entram. Se todos os banheiros estiverem cheios, ou seja, não há mais chaves livres, a contagem do semáforo é 0. Agora, quando eq. uma pessoa sai do banheiro, o semáforo é aumentado para 1 (uma chave grátis) e dado para a próxima pessoa na fila.
Oficialmente: "Um semáforo restringe o número de usuários simultâneos de um recurso compartilhado até um número máximo. Threads podem solicitar acesso ao recurso (diminuindo o semáforo) e podem sinalizar que terminaram de usar o recurso (aumentando o semáforo). " Ref: Symbian Developer Library
Tento não soar maluco, mas não consigo evitar.
Sua pergunta deve ser qual é a diferença entre mutex e semáforos? E para ser mais preciso, a pergunta deveria ser, 'qual é a relação entre mutex e semáforos?'
(Eu teria adicionado essa pergunta, mas estou cem% certo de que algum moderador excessivamente zeloso a fecharia como duplicata, sem entender a diferença entre diferença e relacionamento.)
Na terminologia de objetos, podemos observar que:
observação.1 Semaphore contém mutex
observação.2 Mutex não é semáforo e semáforo não é mutex.
Existem alguns semáforos que agem como se fossem mutex, chamados de semáforos binários, mas NÃO são mutex.
Há um ingrediente especial chamado Signaling (posix usa condition_variable para esse nome), necessário para fazer um Semaphore de mutex. Pense nisso como uma fonte de notificação. Se dois ou mais tópicos estão inscritos na mesma fonte de notificação, então é possível enviá-los mensagem a UM ou a TODOS, para despertar.
Pode haver um ou mais contadores associados a semáforos, que são protegidos por mutex. O cenário mais simples para o semáforo, há um único contador que pode ser 0 ou 1.
É aqui que a confusão flui como uma chuva de monções.
Um semáforo com um contador que pode ser 0 ou 1 NÃO é mutex.
Mutex tem dois estados (0,1) e uma propriedade (tarefa). O semáforo tem um mutex, alguns contadores e uma variável de condição.
Agora, use sua imaginação, e cada combinação de uso de contador e quando sinalizar pode fazer uma espécie de semáforo.
Contador único com valor 0 ou 1 e sinalizando quando o valor vai para 1 E então desbloqueia um dos cara esperando pelo sinal == Semáforo binário
Contador único com valor de 0 a N e sinalizando quando o valor vai para menos de N, e trava / espera quando os valores são N == Semáforo de contagem
Contador único com valor de 0 a N e sinalizando quando o valor vai para N, e bloqueia / espera quando os valores são menores que N == Semáforo de barreira (bem, se eles não o chamarem, então deveriam.)
Agora, a sua pergunta, quando usar o quê. (OU, em vez disso, corrija a pergunta versão.3 quando usar mutex e quando usar semáforo binário, uma vez que não há comparação com o semáforo não binário.) Use mutex quando 1. você quiser um comportamento personalizado, que não é fornecido pelo binário semáforo, tais como spin-lock ou fast-lock ou recursive-locks. Normalmente, você pode personalizar mutexes com atributos, mas personalizar semáforo nada mais é do que escrever um novo semáforo. 2. você deseja primitivo leve OU mais rápido
Use semáforos, quando o que você deseja é exatamente fornecido por ele.
Se você não entender o que está sendo fornecido por sua implementação do semáforo binário, então IMHO, use mutex.
E, por último, leia um livro em vez de confiar apenas no SO.
Acho que a questão deve ser a diferença entre mutex e semáforo binário.
Mutex = É um mecanismo de bloqueio de propriedade, apenas o thread que adquirir o bloqueio pode liberar o bloqueio.
Semáforo binário = É mais um mecanismo de sinalização, qualquer outra thread de maior prioridade pode sinalizar e pegar o bloqueio.
Mutex é para proteger o recurso compartilhado.
O semáforo é para despachar os threads.
Mutex:
Imagine que existem alguns ingressos para vender. Podemos simular um caso em que muitas pessoas compram os ingressos ao mesmo tempo: cada pessoa é um fio condutor para comprar ingressos. Obviamente, precisamos usar o mutex para proteger os tickets porque é o recurso compartilhado.
Semáforo:
imagine que precisamos fazer um cálculo como abaixo:
c = a + b;
Além disso, precisamos de uma função geta()
para calcular a
, uma função getb()
para calcular b
e uma função getc()
para fazer o cálculo c = a + b
.
Obviamente, não podemos fazer o a c = a + b
menos geta()
e getb()
ter sido concluído.
Se as três funções são três threads, precisamos despachar os três threads.
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);
Com a ajuda do semáforo, o código acima pode ter certeza que t3
não vai fazer o seu trabalho até que t1
e t2
ter feito o seu trabalho.
Em uma palavra, o semáforo serve para fazer com que as threads sejam executadas como uma ordem lógica, enquanto que o mutex serve para proteger o recurso compartilhado.
Portanto, eles NÃO são a mesma coisa, mesmo que algumas pessoas sempre digam que mutex é um semáforo especial com o valor inicial 1. Você também pode dizer assim, mas observe que eles são usados em casos diferentes. Não substitua um pelo outro, mesmo que você possa fazer isso.
x = getx(); y = gety(); z = x + y;
Por alguma razão, usamos três threads para fazer as três coisas, agora a ordem dos threads é muito importante porque não podemos fazer a x + y
menos getx
e gety
ter terminado. Em uma palavra, semáforo é usado quando nos preocupamos com a ordem de execução de multi-threading.
x
e y
sejam concluídos, então calcule z = x + y
. Eu sei que o java tem CyclicBarrier
. Além disso, não tenho certeza se posso dizer que mapreduce
é semáforo usecase também, porque não posso reduce
até que todos os map
s sejam concluídos.
Todas as respostas acima são de boa qualidade, mas esta é apenas para memorizar. O nome Mutex é derivado de Mutuamente Exclusivo, portanto, você está motivado a pensar em um bloqueio mutex como Exclusão Mútua entre dois como em apenas um de cada vez, e se eu possuí-lo, você poderá tê-lo somente depois que eu o liberar. Por outro lado, tal caso não existe, pois o Semaphore é como um sinal de trânsito (que a palavra Semáforo também significa).
Como foi apontado, um semáforo com uma contagem de um é a mesma coisa que um semáforo 'binário' que é a mesma coisa que um mutex.
As principais coisas que vi semáforos com uma contagem maior do que um usado para situações de produtor / consumidor em que você tem uma fila de um determinado tamanho fixo.
Você tem dois semáforos então. O primeiro semáforo é inicialmente definido como o número de itens na fila e o segundo semáforo é definido como 0. O produtor faz uma operação P no primeiro semáforo e adiciona à fila. e faz uma operação em V no segundo. O consumidor faz uma operação P no segundo semáforo, remove da fila e, em seguida, faz uma operação V no primeiro.
Desta forma, o produtor é bloqueado sempre que preencher a fila, e o consumidor é bloqueado sempre que a fila está vazia.
Um mutex é um caso especial de semáforo. Um semáforo permite que vários threads entrem na seção crítica. Ao criar um semáforo, você define como os threads são permitidos na seção crítica. É claro que seu código deve ser capaz de lidar com vários acessos a esta seção crítica.
O semáforo binário e o Mutex são diferentes. Da perspectiva do sistema operacional, um semáforo binário e um semáforo de contagem são implementados da mesma maneira e um semáforo binário pode ter um valor 0 ou 1.
Mutex -> Só pode ser usado para um único propósito de exclusão mútua para uma seção crítica do código.
Semáforo -> Pode ser usado para resolver vários problemas. Um semáforo binário pode ser usado para sinalizar e também resolver o problema de exclusão mútua. Quando inicializado em 0 , ele resolve o problema de sinalização e quando inicializado em 1 , ele resolve o problema de exclusão mútua .
Quando o número de recursos é maior e precisa ser sincronizado, podemos usar o semáforo de contagem.
Em meu blog, discuti esses tópicos em detalhes.
https://designpatterns-oo-cplusplus.blogspot.com/2015/07/synchronization-primitives-mutex-and.html