Quando devemos usar mutex e quando devemos usar semáforo

Respostas:

92

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.

Annu Gogatya
fonte
1
adicionar a: semáforos e mutex são duas maneiras de fornecer sincronização. semáforo, pode estar mais relacionado à sinalização (por exemplo, cenário de problema do produtor e consumidor), e mutex, pode estar mais relacionado a permitir o acesso a um por vez (várias solicitações de acesso a recursos compartilhados, mas apenas uma concedida por vez). [artigo interessante: geeksforgeeks.org/mutex-vs-semaphore/]
parasrish
57

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.

paxdiablo
fonte
Ok, também encontrei o semáforo binário. Quando devemos usar o semáforo binário e quando devemos usar mutex?
Karthik Balaguru
Conceitualmente, um semáforo binário é um mutex e é equivalente a um semáforo normal com uma contagem. Pode haver diferenças nas implementações do conceito, como eficiência ou propriedade do recurso (pode ser liberado por alguém que não seja o reivindicador, o que não concordo com a BTW - um recurso só deve ser liberado pelo thread que o reivindicou )
paxdiablo
1
Outra diferença potencial de implementação é o mutex recursivo. Como há apenas um recurso, um único thread pode ter permissão para bloqueá-lo várias vezes (contanto que ele também seja liberado várias vezes). Isso não é tão fácil com um recurso de várias instâncias, pois você pode não saber se o thread deseja reivindicar outra instância ou a mesma instância novamente.
paxdiablo
1
Eles resolvem um problema específico. O fato de que o problema que eles resolvem são as pessoas que não grocam bem mutexes, de forma alguma deve menosprezar a solução :-)
paxdiablo
5
Um mutex é totalmente diferente de um semáforo binário. Desculpe, mas esta definição está errada
Peer Stritzinger
49

É 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

Peer Stritzinger
fonte
Os urls deste site contêm caracteres funky e não funcionam, portanto ... Estou trabalhando nisso
Peer Stritzinger
13

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

Patrick Schlüter
fonte
2
Você está certo. Mesmo se você estiver usando um semáforo com uma contagem de um, está sugerindo algo sobre o que está fazendo do que se usasse um mutex.
Onifário,
Não tenho certeza se concordo com isso, embora não discorde com tanta veemência a ponto de rejeitar você :-) Você diz que o padrão de uso de semáforos é para notificar tópicos, mas é exatamente o que mutexes fazem quando há outro tópico esperando sobre ele, e exatamente o que os semáforos não fazer quando não há segmentos em 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.
paxdiablo
You say that the usage pattern of semaphores is to notify threadsUm ponto sobre a notificação de tópicos. Você pode chamar sem_postde um manipulador de sinal com segurança ( pubs.opengroup.org/onlinepubs/009695399/functions/… ), mas não é recomendado chamar pthread_mutex_locke pthread_mutex_unlockde manipuladores de sinal ( manpages.ubuntu.com/manpages/lucid/man3/… )
@paxdiablo: Há uma grande diferença entre este semáforo binário mutex é manter a contagem de referência. Mutex ou você pode dizer que qualquer mutex condicional não mantém nenhuma contagem relacionada ao bloqueio onde, como sempahore, use para manter a contagem. Portanto, sem_wait e sem_post estão mantendo a contagem.
Prak
9

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

parede de fornalha
fonte
7

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.

  1. 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

  2. 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

  3. 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.

Ajeet Ganga
fonte
5

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.

Saurabh Sengar
fonte
5

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 be uma função getc()para fazer o cálculo c = a + b.

Obviamente, não podemos fazer o a c = a + bmenos 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 t3não vai fazer o seu trabalho até que t1e t2ter 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.

Yves
fonte
Vender ingressos é um bom exemplo. o exemplo do semáforo não está claro (para mim, pelo menos).
prayagupd de
1
@prayagupd O exemplo do Semaphore é fazer tópicos em alguma ordem, enquanto a venda de ingressos não precisa de nenhum pedido. Se houver três pessoas: a, be c. Quando eles vêm para comprar ingressos, não nos importamos com a ordem de compra dos ingressos. No entanto, se fizermos tal cálculo: 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 + ymenos getxe getyter terminado. Em uma palavra, semáforo é usado quando nos preocupamos com a ordem de execução de multi-threading.
Yves de
entendi. Parece uma barreira . Posso dizer que espere até que os threads xe ysejam 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 reduceaté que todos os maps sejam concluídos.
prayagupd de
@prayagupd Sim. Você pode dizer isso.
Yves de
2

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).

Nishant Sondhi
fonte
1

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.

Omniforme
fonte
1

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.

Frode Akselsen
fonte
-1

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

Trapos
fonte