Diferença entre o semáforo binário e o mutex


819

Existe alguma diferença entre um semáforo binário e um mutex ou eles são essencialmente iguais?


11
Eles são semanticamente iguais, mas na prática você notará diferenças estranhas (especialmente no Windows).
9139 Michael Foukarakis

5
@ Michael Foukarakis: Quais são as diferenças estranhas?
Philipp

2
Suponho que estranho não era a expressão correta. Um mutex também suporta propriedade e, às vezes, reentrada. Este é o caso no Windows. Além disso, os semáforos no Windows são implementados sobre os objetos Event, no entanto, não tenho certeza das implicações práticas disso.
Michael Foukarakis


2
@philipxy Escondeu bem 'rn' no lugar de 'm'.
Mooncrater

Respostas:


691

Eles não são a mesma coisa. Eles são usados ​​para diferentes propósitos!
Embora os dois tipos de semáforos tenham um estado cheio / vazio e usem a mesma API, seu uso é muito diferente.

Semáforos
de exclusão mútua Os semáforos de exclusão mútua são usados ​​para proteger recursos compartilhados (estrutura de dados, arquivo, etc.).

Um semáforo Mutex é "pertencente" à tarefa que o executa. Se a Tarefa B tentar fornecer um mutex atualmente retido pela Tarefa A, a chamada da Tarefa B retornará um erro e falhará.

Os mutexes sempre usam a seguinte sequência:

  - SemTake
  - Seção Crítica
  - SemGive

Aqui está um exemplo simples:

  Linha A Linha B
   Tome Mutex
     acessar dados
     ... Tome Mutex <== Bloqueará
     ...
   Forneça dados de acesso ao Mutex <== Desbloqueia
                                  ...
                                Give Mutex

Semáforo
binário O semáforo binário aborda uma questão totalmente diferente:

  • A tarefa B está pendente aguardando que algo aconteça (um sensor sendo acionado, por exemplo).
  • Desarmes do sensor e uma rotina de serviço de interrupção é executada. Ele precisa notificar uma tarefa da viagem.
  • A tarefa B deve executar e executar as ações apropriadas para o disparo do sensor. Então volte a esperar.

   Task A                      Task B
   ...                         Take BinSemaphore   <== wait for something
   Do Something Noteworthy
   Give BinSemaphore           do something    <== unblocks

Observe que, com um semáforo binário, não há problema em B pegar o semáforo e A para fornecê-lo.
Novamente, um semáforo binário NÃO está protegendo um recurso do acesso. O ato de dar e receber um semáforo é fundamentalmente dissociado.
Normalmente, faz pouco sentido para a mesma tarefa dar um dar e receber um mesmo semáforo binário.


12
Um mutex não é melhor que um semáforo binário? Uma vez que não faz sentido se alguém soltar um cadeado que ele realmente não segura.
Pacerier

111
Eles têm propósitos diferentes. O Mutex é para acesso exclusivo a um recurso. Um semáforo binário deve ser usado para sincronização (ou seja, "Ei, alguém! Isso ocorreu!"). O "doador" binário simplesmente notifica quem quer que seja o que estava esperando.
Benoit

5
@Pacerier Você está confundindo o objetivo. Um mutex destina-se a proteger uma região crítica. Você está correto, não faz sentido usar um semáforo binário. Vou atualizar a resposta para explicar o objetivo de cada um.
Benoit

4
@Benoit Então, podemos dizer que o Mutex é usado para atomicidade e o semáforo binário para a perspectiva de pedidos, uma vez que a Tarefa B estará aguardando a Tarefa A sinalizar a liberação do bloqueio, certificando-se de ordenar as operações em uma estrutura de dados?
abhi 23/02

1
@abhi Essa é uma boa maneira de ver o Mutex. No entanto, dependendo do sistema operacional, você pode ter mais de um destinatário aguardando um semáforo binário. Nesse caso, apenas um dos clientes receberá o sem binário. Os outros esperariam por um subsequente. A ordem de recebimento é conhecida ou garantida? Depende do sistema operacional.
Benoit

446
  • Um mutex pode ser liberado apenas pelo encadeamento que o adquiriu .
  • Um semáforo binário pode ser sinalizado por qualquer encadeamento (ou processo).

portanto, os semáforos são mais adequados para alguns problemas de sincronização, como produtor-consumidor.

No Windows, os semáforos binários são mais como objetos de eventos do que mutexes.


34
Mutex can be released only by thread that had acquired it- Eu apenas tentei com um programa baseado simples pthread_mutex, um thread pode desbloquear mutex bloqueado no segmento principal
daisy

15
@ warl0ck Conforme a página de manual do pthread_mutex_lock linux.die.net/man/3/pthread_mutex_lock : "Se o tipo de mutex for PTHREAD_MUTEX_ERRORCHECK, a verificação de erros será fornecida .... Se um thread tentar desbloquear um mutex que possui não bloqueado ou um mutex desbloqueado, um erro será retornado. "
Amit

47
@ warl0ck Consulte stackoverflow.com/a/5492499/385064 'O Pthreads possui 3 tipos diferentes de mutexes: Mutex rápido, mutex recursivo e verificação de erro. Você usou um mutex rápido que, por motivos de desempenho, não verifica esse erro. Se você usar a verificação de erro do mutex no Linux, encontrará os resultados esperados. '
FrostNovaZzz

1
Em nosso código, usamos o mutex também para fins de sincronização. O Thread que bloqueia o mutex novamente tentou bloquear o mutex.Em seguida, ele entra no estado bloqueado.O que vimos é que somos capazes de desbloquear isso de outro thread. Estamos usando o padrão posix apenas. Portanto, a principal diferença entre o mutex e o semáforo binário parece vaga.
achoora 18/02/16

1
@achoora Concordo que é errado especializar o semáforo para sincronização. Na verdade, todos os pipelines mutex, semáforo binário, barreira e são padrões diferentes para sincronização. Na perspectiva do design, o mutex é mais parecido com o padrão de estado, em que o algoritmo selecionado pelo estado pode alterar o estado. O semáforo binário é mais parecido com o padrão de estratégia, onde o algoritmo externo pode mudar o estado e, eventualmente, o algoritmo / estratégia selecionado para execução.
Shuva 17/05

442

O exemplo do WC é uma analogia agradável:

Mutex:

É a chave para um banheiro. Uma pessoa pode ter a chave - ocupar o banheiro - no momento. Quando termina, a pessoa fornece (libera) a chave para a próxima pessoa na fila.

Oficialmente: "Os mutexes geralmente são usados ​​para serializar o acesso a uma seção do código reentrante que não pode ser executada 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 nessa seção para aguardar até que o primeiro thread saia dessa seção ". Ref: Biblioteca do desenvolvedor Symbian

(Um mutex é realmente um semáforo com o 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 de semáforos - a contagem de chaves - é definida como 4 no início (todos os quatro banheiros são gratuitos), então o valor da contagem é diminuído à medida que as pessoas entram. Se todos os banheiros estiverem cheios, por exemplo. não há chaves livres restantes, a contagem de semáforos é 0. Agora, quando eq. uma pessoa sai do banheiro, o semáforo é aumentado para 1 (uma chave livre) e entregue à 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. Os encadeamentos podem solicitar acesso ao recurso (diminuindo o semáforo) e podem sinalizar que eles terminaram de usar o recurso (incrementando o semáforo). " Ref: Biblioteca do desenvolvedor Symbian


234
... mas isso é sobre mutex vs semáforo de contagem. A pergunta foi feita sobre binário.
Roman Nikitchenko

24
Enquanto o que é dito por david está correto, mas NÃO é a resposta para a pergunta. A resposta de Mladen Jankovic é a resposta à pergunta, onde é preciso apontar para diferenciar "semáforo binário" vs "mutex".
Ajeet Ganga

13
Infelizmente, essa resposta incorreta tem mais votos que a melhor resposta por @Benoit
NeonGlow

6
Esta resposta é enganosa. Só deveria ter sido comparada com o Semáforo Binário.
Hemanth 15/03/14

3
Isso também demonstra um problema com o uso de um semáforo de contagem para proteger um recurso compartilhado: se as chaves são realmente idênticas e um banheiro é desbloqueado usando uma chave, e não há outro mecanismo para distribuir o uso do cubículo, então: (1) o primeiro O usuário desbloqueia, entra e começa a usar o primeiro cubículo. (2) os próximos desbloqueia usuário, entra e começa a usar o primeiro cubículo ...
Technophile

151

Bons artigos sobre o tema:

Da parte 2:

O mutex é semelhante aos princípios do semáforo binário com uma diferença significativa: o princípio da propriedade. Propriedade é o conceito simples de que, quando uma tarefa trava (adquire) um mutex, somente ele pode desbloqueá-lo (liberá-lo). Se uma tarefa tentar desbloquear um mutex, ele não foi bloqueado (portanto, não possui), uma condição de erro será encontrada e, mais importante, o mutex não será desbloqueado. Se o objeto de exclusão mútua não possui propriedade, irrelevante o que é chamado, não é um mutex.


Obrigado pelo link, as explicações são excelentes. O link mudou: feabhas.com/blog/2009/09/… (Use <Anterior e Próximo> para navegar para os outros dois artigos.
Aaron H.

@Aaron Corrigi os links
Juiz Maygarden

Nota - a falta de propriedade também impede o sistema operacional de contornar a inversão de prioridade. Por esse motivo, geralmente uso variáveis ​​de condição em vez de semáforos para arquiteturas de produtores / consumidores.
precisa saber é o seguinte

1
+1 inimigo excelentes links para artigos. O melhor artigo que explica o semáforo e o mutex com "o que é" e "o que faz" computing.llnl.gov/tutorials/pthreads Eu usei este artigo como minha referência nos bastidores, que tecnicamente explica tudo sobre mutex / condicionais e outras construções construídas em sua parte superior como semáforo / barreira / leitor-escritor, mas em nenhum lugar explícito e conciso sobre os problemas enfrentados pelas construções. Em suma, é referência. :)
Ajeet Ganga

mais facilmente compreendido do que as outras respostas.
BinaryTreeee

101

Como nenhuma das respostas acima elimina a confusão, aqui está uma que esclareceu minha confusão.

A rigor, um mutex é um mecanismo de bloqueio usado para sincronizar o acesso a um recurso. Somente uma tarefa (pode ser um encadeamento ou processo baseado na abstração do SO) pode adquirir o mutex. Isso significa que haverá propriedade associada ao mutex e apenas o proprietário poderá liberar o bloqueio (mutex).

O semáforo é um mecanismo de sinalização (tipo de sinal "Estou pronto, você pode continuar"). Por exemplo, se você estiver ouvindo músicas (assuma isso como uma tarefa) no seu celular e ao mesmo tempo que seu amigo ligou para você, uma interrupção será acionada, na qual uma rotina de serviço de interrupção (ISR) sinalizará a tarefa de processamento de chamadas para ativar .

Fonte: http://www.geeksforgeeks.org/mutex-vs-semaphore/


42

Sua semântica de sincronização é muito diferente:

  • Os mutexes permitem a serialização do acesso a um determinado recurso, ou seja, vários threads aguardam um bloqueio, um de cada vez e, como foi dito anteriormente, o thread possui o bloqueio até que seja concluído: somente esse segmento específico pode desbloqueá-lo.
  • um semáforo binário é um contador com os valores 0 e 1: uma tarefa bloqueada até que qualquer tarefa faça um sem_post. O semáforo anuncia que um recurso está disponível e fornece o mecanismo para aguardar até que seja sinalizado como disponível.

Como tal, pode-se ver um mutex como um token transmitido de tarefa para tarefa e um semáforo como sinal vermelho de trânsito ( indica a alguém que pode prosseguir).


23

No nível teórico, eles não são diferentes semanticamente. Você pode implementar um mutex usando semáforos ou vice-versa (veja aqui um exemplo). Na prática, a implementação é diferente e eles oferecem serviços ligeiramente diferentes.

A diferença prática (em termos de serviços do sistema que os cerca) é que a implementação de um mutex visa ser um mecanismo de sincronização mais leve. No oráculo, os mutexes são conhecidos como trincos e os semáforos são conhecidos como esperas .

No nível mais baixo, eles usam algum tipo de teste atômico e mecanismo definido . Isso lê o valor atual de um local de memória, calcula algum tipo de condicional e grava um valor nesse local em uma única instrução que não pode ser interrompida . Isso significa que você pode adquirir um mutex e testar para ver se mais alguém o teve antes de você.

Uma implementação típica do mutex possui um processo ou thread executando a instrução test-and-set e avaliando se alguma outra coisa configurou o mutex. Um ponto importante aqui é que não há interação com o agendador , portanto, não temos idéia (e não nos importamos) de quem definiu o bloqueio. Em seguida, desistimos da nossa fatia de tempo e tentamos novamente quando a tarefa é reprogramada ou executamos um bloqueio de rotação . Um bloqueio de rotação é um algoritmo como:

Count down from 5000:
     i. Execute the test-and-set instruction
    ii. If the mutex is clear, we have acquired it in the previous instruction 
        so we can exit the loop
   iii. When we get to zero, give up our time slice.

Quando terminamos de executar nosso código protegido (conhecido como seção crítica ), apenas definimos o valor mutex como zero ou o que significa 'claro'. Se várias tarefas estiverem tentando adquirir o mutex, a próxima tarefa agendada após o lançamento do mutex terá acesso ao recurso. Normalmente, você usaria mutexes para controlar um recurso sincronizado no qual o acesso exclusivo é necessário apenas por períodos muito curtos, normalmente para fazer uma atualização em uma estrutura de dados compartilhada.

Um semáforo é uma estrutura de dados sincronizada (normalmente usando um mutex) que possui uma contagem e alguns wrappers de chamada do sistema que interagem com o planejador com um pouco mais de profundidade do que as bibliotecas mutex. Os semáforos são incrementados e decrementados e usados ​​para bloquear tarefas até que outra coisa esteja pronta. Consulte Problema do produtor / consumidor para obter um exemplo simples disso. Os semáforos são inicializados com algum valor - um semáforo binário é apenas um caso especial em que o semáforo é inicializado como 1. A postagem em um semáforo tem o efeito de ativar um processo de espera.

Um algoritmo básico de semáforo se parece com:

(somewhere in the program startup)
Initialise the semaphore to its start-up value.

Acquiring a semaphore
   i. (synchronised) Attempt to decrement the semaphore value
  ii. If the value would be less than zero, put the task on the tail of the list of tasks waiting on the semaphore and give up the time slice.

Posting a semaphore
   i. (synchronised) Increment the semaphore value
  ii. If the value is greater or equal to the amount requested in the post at the front of the queue, take that task off the queue and make it runnable.  
 iii. Repeat (ii) for all tasks until the posted value is exhausted or there are no more tasks waiting.

No caso de um semáforo binário, a principal diferença prática entre os dois é a natureza dos serviços do sistema em torno da estrutura de dados real.

EDIT: Como evan apontou com razão, os spinlocks desaceleram uma máquina de processador único. Você usaria apenas um spinlock em uma caixa com vários processadores, porque em um único processador o processo que contém o mutex nunca o redefinirá enquanto outra tarefa estiver em execução. Spinlocks são úteis apenas em arquiteturas com vários processadores.


1
Eu não acho que seja uma prática comum que um mutex seja implementado com spinlocks. Em uma máquina Uni-proc, isso seria absolutamente terrível para o desempenho.
Evan Teran

Normalmente você usaria apenas spinlocks em sistemas com vários processadores.
ConcernedOfTunbridgeWells

Mesmo no SMP, depois de girar algumas vezes, você volta ao sono / vigília assistida por SO. (por exemplo, a futexchamada do sistema Linux existe para ajudar as implementações de mutex / semáforo de espaço de usuário de baixa latência. en.wikipedia.org/wiki/Futex ) No caminho rápido sem contenção, ou se o recurso for disponibilizado em breve, você nunca terá a sobrecarga de uma chamada do sistema. Mas você não gasta mais do que alguns microssegundos ocupados em espera (girando). O ajuste dos parâmetros de retorno e espera do loop de rotação depende do hardware e da carga de trabalho, é claro, mas a biblioteca padrão geralmente tem opções razoáveis.
Peter Cordes

19

Embora mutex e semáforos sejam usados ​​como primitivos de sincronização, há uma grande diferença entre eles. No caso do mutex, apenas o encadeamento que bloqueou ou adquiriu o mutex pode desbloqueá-lo. No caso de um semáforo, um encadeamento aguardando um semáforo pode ser sinalizado por um encadeamento diferente. Alguns sistemas operacionais suportam o uso de mutex e semáforos entre processos. Normalmente, o uso é criado na memória compartilhada.


"pode ​​ser sinalizado por um segmento diferente", o que significa dar um exemplo.
Myanju 17/08/19

15

Mutex: Suponha que o segmento de seção crítica T1 queira acessá-lo e siga as etapas abaixo. T1:

  1. Bloquear
  2. Usar seção crítica
  3. Desbloquear

Semáforo binário: funciona com base em sinalização de espera e sinal. espera (s) diminui o valor "s" em um geralmente o valor "s" é inicializado com o valor "1", sinal (es) aumenta o valor "s" em um. se o valor "s" for 1 significa que ninguém está usando a seção crítica, quando valor for 0 significa que a seção crítica está em uso. suponha que o segmento T2 esteja usando a seção crítica e siga as etapas abaixo. T2:

  1. wait (s) // inicialmente o valor é um após a chamada wait, seu valor diminui em um, ou seja, 0
  2. Usar seção crítica
  3. sinal (es) // agora o valor s é aumentado e se torna 1

A principal diferença entre o mutex e o semáforo binário está no Mutext se o thread bloquear a seção crítica, então ele tem que desbloquear a seção crítica, nenhum outro thread pode desbloqueá-lo, mas no caso do semáforo binário, se um thread bloqueia a seção crítica usando a função wait (s) e, em seguida, valor de s se torna "0" e ninguém pode acessá-lo até que o valor de "s" se torne 1, mas suponha que alguns outros chamados de thread sinalizem que o valor de "s" se torne 1 e permite que outra função use a seção crítica. portanto, no segmento de semáforo binário não tem propriedade.


12

No Windows, existem duas diferenças entre mutexes e semáforos binários:

  1. Um mutex só pode ser liberado pelo encadeamento que possui propriedade, ou seja, o encadeamento que anteriormente chamava a função Wait (ou que assumiu a propriedade ao criá-lo). Um semáforo pode ser liberado por qualquer thread.

  2. Um encadeamento pode chamar uma função de espera repetidamente em um mutex sem bloquear. No entanto, se você chamar uma função de espera duas vezes em um semáforo binário sem liberar o semáforo no meio, o encadeamento será bloqueado.


4
Boa resposta. No item 2, você está descrevendo um mutex recursivo - nem todos os mutexes são necessariamente recursivos. Por exemplo, cs.wustl.edu/~schmidt/ACE.FAQ.html#Q14
Dan

10

Obviamente, você usa o mutex para bloquear dados em um thread acessado por outro thread ao mesmo tempo. Suponha que você acabou de ligar lock()e no processo de acesso aos dados. Isso significa que você não espera que nenhum outro thread (ou outra instância do mesmo código de thread) acesse os mesmos dados bloqueados pelo mesmo mutex. Ou seja, se é o mesmo código de thread sendo executado em uma instância de thread diferente, bate no bloqueio, então olock()deve bloquear o fluxo de controle lá. Isso se aplica a um encadeamento que usa um código de encadeamento diferente, que também acessa os mesmos dados e também é bloqueado pelo mesmo mutex. Nesse caso, você ainda está acessando os dados e poderá levar, digamos, mais 15 segundos para alcançar o desbloqueio do mutex (para que o outro encadeamento bloqueado no bloqueio do mutex seja desbloqueado e permita que o controle acessar os dados). Você, a qualquer custo, permite que outro encadeamento desbloqueie o mesmo mutex e, por sua vez, permita que o encadeamento que já está aguardando (bloqueando) no bloqueio do mutex desbloqueie e acesse os dados? Espero que você entenda o que estou dizendo aqui? Conforme definido na definição universal !,

  • com "mutex" isso não pode acontecer. Nenhuma outra linha pode desbloquear a trava na sua linha
  • com o "semáforo binário" isso pode acontecer. Qualquer outra thread pode desbloquear a trava na sua thread

Portanto, se você é muito específico sobre o uso de semáforo binário em vez de mutex, deve ter muito cuidado em "definir o escopo" dos bloqueios e desbloqueios. Quero dizer que todo fluxo de controle que atinge cada bloqueio deve atingir uma chamada de desbloqueio, também não deve haver nenhum “primeiro desbloqueio”, mas sempre deve ser “primeiro bloqueio”.


10

Mutex são usados ​​para "Mecanismos de Bloqueio". um processo de cada vez pode usar um recurso compartilhado

enquanto que

Os semáforos são usados ​​para "Mecanismos de sinalização" como "Estou pronto, agora posso continuar"


9

Mito:

Alguns artigos dizem que "o semáforo binário e o mutex são iguais" ou "o semáforo com o valor 1 é mutex", mas a diferença básica é que o Mutex pode ser liberado apenas pelo segmento que o adquiriu, enquanto você pode sinalizar o semáforo de qualquer outro segmento

Pontos chave:

• Um encadeamento pode adquirir mais de um bloqueio (Mutex).

• Um mutex pode ser bloqueado mais de uma vez apenas se for um mutex recursivo; aqui, bloquear e desbloquear para mutex deve ser o mesmo

• Se um encadeamento que já havia bloqueado um mutex, tentar bloqueá-lo novamente, ele entrará na lista de espera desse mutex, o que resultará em um impasse.

• O semáforo binário e o mutex são semelhantes, mas não iguais.

• O Mutex é uma operação cara devido aos protocolos de proteção associados a ele.

• O objetivo principal do mutex é obter acesso atômico ou bloquear recursos


8

Um Mutex controla o acesso a um único recurso compartilhado. Ele fornece operações para adquirir () acesso a esse recurso e liberá- lo () quando concluído.

Um semáforo controla o acesso a um conjunto compartilhado de recursos. Ele fornece operações para Wait () até que um dos recursos do pool fique disponível e Signal () quando ele é devolvido ao pool.

Quando o número de recursos que um semáforo protege é maior que 1, é chamado de semáforo de contagem . Quando ele controla um recurso, é chamado de Semáforo Booleano . Um semáforo booleano é equivalente a um mutex.

Assim, um semáforo é uma abstração de nível mais alto que o Mutex. Um Mutex pode ser implementado usando um semáforo, mas não o contrário.


6

A pergunta modificada é - Qual é a diferença entre um mutex e um semáforo "binário" no "Linux"?

Resp: A seguir estão as diferenças - i) Escopo - O escopo do mutex está dentro de um espaço de endereço do processo que o criou e é usado para sincronização de encadeamentos. Enquanto o semáforo pode ser usado no espaço do processo e, portanto, pode ser usado para sincronização entre processos.

ii) O Mutex é leve e mais rápido que o semáforo. Futex é ainda mais rápido.

iii) O Mutex pode ser adquirido pelo mesmo encadeamento com êxito várias vezes, com a condição de liberá-lo o mesmo número de vezes. Outro segmento que tentar adquirir será bloqueado. Enquanto no caso do semáforo, se o mesmo processo tentar adquiri-lo novamente, ele bloqueia, pois pode ser adquirido apenas uma vez.


Eu erro. ii) Fonte? iii) Depende.
curiousguy

6

Diferença entre o semáforo binário e o Mutex: PROPRIEDADE: os semáforos podem ser sinalizados (publicados) mesmo de um proprietário não atual. Isso significa que você pode simplesmente postar a partir de qualquer outro tópico, embora você não seja o proprietário.

O semáforo é uma propriedade pública em processo, pode ser simplesmente postada por um thread não proprietário. Por favor, marque essa diferença nas letras BOLD, significa muito.


5

O trabalho da Mutex sobre o bloqueio da região crítica, mas o Semaphore trabalha em contagem.



4

Além do fato de os mutexes terem um proprietário, os dois objetos podem ser otimizados para uso diferente. Os mutexes são projetados para serem mantidos apenas por um curto período de tempo; violar isso pode causar desempenho ruim e agendamento injusto. Por exemplo, um segmento em execução pode ter permissão para adquirir um mutex, mesmo que outro segmento já esteja bloqueado nele. Os semáforos podem fornecer mais justiça, ou a justiça pode ser forçada usando várias variáveis ​​de condição.


Em quais casos específicos é garantida a justiça para os semáforos, mas não para os mutexes?
curiousguy

1
POSIX tem requisitos específicos que segmento deve ser despertado por sem_post()para SCHED_FIFOe SCHED_RR(ambos estes não são padrão): o maior thread de prioridade, e se houver múltiplos com a mesma prioridade, o segmento que tem sido esperando por mais tempo. O OpenSolaris segue essa regra FIFO até certo ponto, mesmo para agendamento normal. Para o glibc e o FreeBSD, desbloquear um mutex simples (por exemplo, sem proteção de prioridade ou herança de prioridade) e postar um semáforo são basicamente os mesmos, marcando o objeto como desbloqueado e, se houver threads em espera, chamando o kernel para ativar um.
Jilles

4

No Windows, a diferença é a seguinte. MUTEX: o processo que executa com êxito a espera deve executar um sinal e vice-versa. SEMÁFORES BINÁRIOS: Diferentes processos podem executar operações de espera ou sinalização em um semáforo.


4

Embora um semáforo binário possa ser usado como um mutex, um mutex é um caso de uso mais específico, pois apenas o processo que bloqueou o mutex deve desbloqueá-lo. Essa restrição de propriedade torna possível fornecer proteção contra:

  • Liberação acidental
  • Impasse Recursivo
  • Tarefa Deadlock

Essas restrições nem sempre estão presentes porque degradam a velocidade. Durante o desenvolvimento do seu código, você pode ativar essas verificações temporariamente.

por exemplo, você pode ativar o atributo de verificação de erro no seu mutex. O erro ao verificar os mutexes retorna EDEADLKse você tentar bloquear o mesmo duas vezes e EPERMse desbloquear um mutex que não seja seu.

pthread_mutex_t mutex;
pthread_mutexattr_t attr;
pthread_mutexattr_init (&attr);
pthread_mutexattr_settype (&attr, PTHREAD_MUTEX_ERRORCHECK_NP);
pthread_mutex_init (&mutex, &attr);

Depois de inicializados, podemos colocar essas verificações em nosso código da seguinte maneira:

if(pthread_mutex_unlock(&mutex)==EPERM)
 printf("Unlock failed:Mutex not owned by this thread\n");

4

O conceito ficou claro para mim depois de passar por cima das postagens. Mas havia algumas perguntas remanescentes. Então, eu escrevi este pequeno pedaço de código.

Quando tentamos dar um semáforo sem pegá-lo, ele passa. Mas, quando você tenta dar um mutex sem tomá-lo, ele falha. Eu testei isso em uma plataforma Windows. Habilite USE_MUTEX para executar o mesmo código usando um MUTEX.

#include <stdio.h>
#include <windows.h>
#define xUSE_MUTEX 1
#define MAX_SEM_COUNT 1

DWORD WINAPI Thread_no_1( LPVOID lpParam );
DWORD WINAPI Thread_no_2( LPVOID lpParam );

HANDLE Handle_Of_Thread_1 = 0;
HANDLE Handle_Of_Thread_2 = 0;
int Data_Of_Thread_1 = 1;
int Data_Of_Thread_2 = 2;
HANDLE ghMutex = NULL;
HANDLE ghSemaphore = NULL;


int main(void)
{

#ifdef USE_MUTEX
    ghMutex = CreateMutex( NULL, FALSE, NULL);
    if (ghMutex  == NULL) 
    {
        printf("CreateMutex error: %d\n", GetLastError());
        return 1;
    }
#else
    // Create a semaphore with initial and max counts of MAX_SEM_COUNT
    ghSemaphore = CreateSemaphore(NULL,MAX_SEM_COUNT,MAX_SEM_COUNT,NULL);
    if (ghSemaphore == NULL) 
    {
        printf("CreateSemaphore error: %d\n", GetLastError());
        return 1;
    }
#endif
    // Create thread 1.
    Handle_Of_Thread_1 = CreateThread( NULL, 0,Thread_no_1, &Data_Of_Thread_1, 0, NULL);  
    if ( Handle_Of_Thread_1 == NULL)
    {
        printf("Create first thread problem \n");
        return 1;
    }

    /* sleep for 5 seconds **/
    Sleep(5 * 1000);

    /*Create thread 2 */
    Handle_Of_Thread_2 = CreateThread( NULL, 0,Thread_no_2, &Data_Of_Thread_2, 0, NULL);  
    if ( Handle_Of_Thread_2 == NULL)
    {
        printf("Create second thread problem \n");
        return 1;
    }

    // Sleep for 20 seconds
    Sleep(20 * 1000);

    printf("Out of the program \n");
    return 0;
}


int my_critical_section_code(HANDLE thread_handle)
{

#ifdef USE_MUTEX
    if(thread_handle == Handle_Of_Thread_1)
    {
        /* get the lock */
        WaitForSingleObject(ghMutex, INFINITE);
        printf("Thread 1 holding the mutex \n");
    }
#else
    /* get the semaphore */
    if(thread_handle == Handle_Of_Thread_1)
    {
        WaitForSingleObject(ghSemaphore, INFINITE);
        printf("Thread 1 holding semaphore \n");
    }
#endif

    if(thread_handle == Handle_Of_Thread_1)
    {
        /* sleep for 10 seconds */
        Sleep(10 * 1000);
#ifdef USE_MUTEX
        printf("Thread 1 about to release mutex \n");
#else
        printf("Thread 1 about to release semaphore \n");
#endif
    }
    else
    {
        /* sleep for 3 secconds */
        Sleep(3 * 1000);
    }

#ifdef USE_MUTEX
    /* release the lock*/
    if(!ReleaseMutex(ghMutex))
    {
        printf("Release Mutex error in thread %d: error # %d\n", (thread_handle == Handle_Of_Thread_1 ? 1:2),GetLastError());
    }
#else
    if (!ReleaseSemaphore(ghSemaphore,1,NULL) )      
    {
        printf("ReleaseSemaphore error in thread %d: error # %d\n",(thread_handle == Handle_Of_Thread_1 ? 1:2), GetLastError());
    }
#endif

    return 0;
}

DWORD WINAPI Thread_no_1( LPVOID lpParam ) 
{ 
    my_critical_section_code(Handle_Of_Thread_1);
    return 0;
}


DWORD WINAPI Thread_no_2( LPVOID lpParam ) 
{
    my_critical_section_code(Handle_Of_Thread_2);
    return 0;
}

O simples fato de o semáforo permitir sinalizar "é feito usando um recurso", mesmo que nunca tenha sido o proprietário, me faz pensar que há um acoplamento muito frouxo entre possuir e sinalizar no caso de semáforos.


Se você ler as outras respostas, fica claro que o conceito de "propriedade" só faz sentido com mutexes, não semáforos. Semáforos podem ser usados ​​para coisas como um encadeamento, informando outros encadeamentos que o processamento de um pedaço de dados é feito; resultados prontos para serem lidos.
Peter Cordes

2

O Mutex é usado para proteger o código e os dados confidenciais, o semáforo é usado para a sincronização. Você também pode ter um uso prático com a proteção do código confidencial, mas pode haver um risco de liberar a proteção pelo outro encadeamento pela operação V. A diferença entre bi-semáforo e mutex é a propriedade. Por exemplo, no banheiro, o Mutex é como alguém que pode entrar no banheiro e trancar a porta, ninguém mais pode entrar até que o homem saia, o bi-semáforo é como aquele que pode entrar o banheiro e trancar a porta, mas alguém poderia entrar pedindo ao administrador para abrir a porta, é ridículo.


2

Mutex

Os mutexes geralmente são usados ​​para serializar o acesso a uma seção do código reentrante que não pode ser executada simultaneamente por mais de um thread. Um objeto mutex permite apenas um encadeamento em uma seção controlada, forçando outros encadeamentos que tentam obter acesso a essa seção a aguardar até que o primeiro encadeamento saia dessa seção.O uso inadequado de um mutex é proteger um recurso compartilhado. efeito colateral não intencional. Quaisquer duas tarefas do RTOS que operam com prioridades diferentes e coordenadas por meio de um mutex criam a oportunidade de inversão de prioridade . O Mutex trabalha no espaço do usuário .

Semáforo

O semáforo é um mecanismo de sinalização. O semáforo restringe o número de usuários simultâneos de um recurso compartilhado até um número máximo. Os encadeamentos podem solicitar acesso ao recurso (decrementando o semáforo) e podem sinalizar que eles terminaram de usar o recurso (incrementando o semáforo). Ele permite que o número de threads acesse recursos compartilhados. O uso correto de um semáforo é para sinalizar de uma tarefa para outra. Os semáforos também podem ser usados ​​para sinalizar de uma rotina de serviço de interrupção (ISR) para uma tarefa. A sinalização de um semáforo é um comportamento RTOS sem bloqueio e, portanto, seguro para ISR. Como essa técnica elimina a necessidade propensa a erros de desativar interrupções no nível da tarefa. Isso funciona no espaço do kernel .


1

A resposta pode depender do sistema operacional de destino. Por exemplo, pelo menos uma implementação RTOS com a qual estou familiarizado permitirá várias operações sequenciais de "obtenção" em um único mutex do SO, desde que todas elas estejam no mesmo contexto de encadeamento. Os múltiplo get devem ser substituídos por um número igual de put antes que outro thread possa obter o mutex. Isso difere dos semáforos binários, para os quais apenas uma única obtenção é permitida por vez, independentemente dos contextos de encadeamento.

A idéia por trás desse tipo de mutex é que você protege um objeto, permitindo apenas que um único contexto modifique os dados por vez. Mesmo que o thread obtenha o mutex e, em seguida, chame uma função que modifique ainda mais o objeto (e obtenha / coloque o mutex protetor em torno de suas próprias operações), as operações ainda deverão ser seguras, porque todas elas estão acontecendo em um único thread.

{
    mutexGet();  // Other threads can no longer get the mutex.

    // Make changes to the protected object.
    // ...

    objectModify();  // Also gets/puts the mutex.  Only allowed from this thread context.

    // Make more changes to the protected object.
    // ...

    mutexPut();  // Finally allows other threads to get the mutex.
}

Obviamente, ao usar esse recurso, você deve ter certeza de que todos os acessos em um único thread são realmente seguros!

Não tenho certeza de quão comum é essa abordagem ou se ela se aplica fora dos sistemas com os quais estou familiarizado. Para um exemplo desse tipo de mutex, consulte o ThreadX RTOS.


2
O tipo de mutex do qual você está falando é chamado de "mutex recursivo" e deve ser evitado, pois é lento e tende a promover um design ruim: (consulte David Butenhof: zaval.org/resources/library/butenhof1.html )
gaspard

Acordado. Neste SO em particular, eu uso o serviço mutex, onde quero deixar claro que o código é para "exclusão mútua" e não para contagem de referência, mas não uso o recurso recursivo por medo de desanexação feia. Ainda assim, no contexto da pergunta, essa é uma diferença importante entre um "mutex" e um "semáforo binário".
Casey Barker

1

Os mutexes têm propriedade, diferentemente dos semáforos. Embora qualquer encadeamento, dentro do escopo de um mutex, possa obter um mutex desbloqueado e bloquear o acesso à mesma seção crítica do código, apenas o encadeamento que bloqueou um mutex deve desbloqueá-lo .


o que é propriedade? Você quer dizer que o contexto que adquire o mutex só pode desassociá-lo?
Raulp 30/05

1

Como muitas pessoas mencionaram aqui, um mutex é usado para proteger um trecho de código crítico (seção crítica AKA). Você irá adquirir o mutex (bloqueio), entrar na seção crítica e liberar o mutex (desbloqueio) no mesmo encadeamento .

Ao usar um semáforo, você pode fazer um thread aguardar em um semáforo (por exemplo, segmento A), até que outro segmento (por exemplo, segmento B) conclua qualquer tarefa e, em seguida, defina o Semáforo para o segmento A para interromper a espera e continuar sua tarefa.


1

Melhor solução

A única diferença é

1.Mutex -> lock e unlock estão sob a propriedade de um segmento que bloqueia o mutex.

2.Semaphore -> Sem propriedade, ou seja; se um thread chamar semwait (s), qualquer outro thread poderá chamar sempost (s) para remover a trava.


1

MUTEX

Até recentemente, o único bloqueio para dormir no kernel era o semáforo. A maioria dos usuários de semáforos instanciava um semáforo com uma contagem de um e os tratava como uma trava de exclusão mútua - uma versão adormecida da trava giratória. Infelizmente, os semáforos são bastante genéricos e não impõem restrições de uso. Isso os torna úteis para gerenciar o acesso exclusivo em situações obscuras, como danças complicadas entre o kernel e o espaço do usuário. Mas isso também significa que o bloqueio mais simples é mais difícil de fazer, e a falta de regras aplicadas torna impossível qualquer tipo de depuração automatizada ou aplicação de restrições. Buscando um bloqueio simples para dormir, os desenvolvedores do kernel introduziram o mutex. Sim, como você já está acostumado, esse é um nome confuso. Vamos esclarecer. O termo "mutex" é um nome genérico para se referir a qualquer cadeado que imponha exclusão mútua, como um semáforo com uma contagem de uso de um. Nos kernels recentes do Linux, o nome próprio "mutex" agora também é um tipo específico de bloqueio de suspensão que implementa exclusão mútua. Ou seja, um mutex é um mutex.

A simplicidade e eficiência do mutex vêm das restrições adicionais impostas a seus usuários além do que o semáforo exige. Diferentemente de um semáforo, que implementa o comportamento mais básico de acordo com o design original de Dijkstra, o mutex possui um caso de uso mais restrito e restrito: n Somente uma tarefa pode reter o mutex por vez. Ou seja, a contagem de uso em um mutex é sempre uma.

  1. Quem bloqueou um mutex deve desbloqueá-lo. Ou seja, você não pode bloquear um mutex em um contexto e desbloqueá-lo em outro. Isso significa que o mutex não é adequado para sincronizações mais complicadas entre o kernel e o espaço do usuário. A maioria dos casos de uso, no entanto, bloqueia e desbloqueia de maneira limpa no mesmo contexto.
  2. Bloqueios e desbloqueios recursivos não são permitidos. Ou seja, você não pode adquirir recursivamente o mesmo mutex e não pode desbloquear um mutex desbloqueado.
  3. Um processo não pode sair enquanto mantém um mutex.
  4. Um mutex não pode ser adquirido por um manipulador de interrupções ou pela metade inferior, mesmo com mutex_trylock ().
  5. Um mutex pode ser gerenciado apenas por meio da API oficial: ele deve ser inicializado pelos métodos descritos nesta seção e não pode ser copiado, inicializado manualmente ou reinicializado.

[1] Desenvolvimento de Kernel Linux, Terceira Edição Robert Love


1

Acho que a maioria das respostas aqui foram confusas, especialmente aquelas que dizem que o mutex pode ser liberado apenas pelo processo que o contém, mas o semáforo pode ser sinalizado por qualquer processo. A linha acima é meio vaga em termos de semáforo. Para entender, devemos saber que existem dois tipos de semáforo: um é chamado semáforo de contagem e o outro é chamado de semáforo binário. Na contagem, o semáforo lida com o acesso a n número de recursos em que n pode ser definido antes do uso. Cada semáforo possui uma variável de contagem, que mantém a contagem do número de recursos em uso, inicialmente, é definido como n. Cada processo que deseja usar um recurso executa uma operação wait () no semáforo (diminuindo a contagem). Quando um processo libera um recurso, ele executa uma operação release () (incrementando a contagem). Quando a contagem se torna 0, todos os recursos estão sendo usados. Depois disso, o processo aguarda até que a contagem se torne maior que 0. Agora, aqui está o problema: apenas o processo que contém o recurso pode aumentar a contagem; nenhum outro processo pode aumentar a contagem; apenas os processos que mantêm um recurso podem aumentar a contagem e o processo. esperar pelo semáforo novamente e, quando vê o recurso disponível, diminui a contagem novamente. Portanto, em termos de semáforo binário, apenas o processo que contém o semáforo pode aumentar a contagem, e a contagem permanece zero até que ele pare de usar o semáforo e aumente a contagem e outro processo tenha a chance de acessar o semáforo. Agora, aqui está o problema: apenas o processo que retém o recurso pode aumentar a contagem; nenhum outro processo pode aumentar a contagem; apenas os processos que mantêm um recurso podem aumentar a contagem e o processo aguardando o semáforo verifica novamente e, quando vê o recurso disponível, diminui a contagem novamente. Portanto, em termos de semáforo binário, apenas o processo que contém o semáforo pode aumentar a contagem, e a contagem permanece zero até que ele pare de usar o semáforo e aumente a contagem e outro processo tenha a chance de acessar o semáforo. Agora, aqui está o problema: apenas o processo que retém o recurso pode aumentar a contagem; nenhum outro processo pode aumentar a contagem; apenas os processos que mantêm um recurso podem aumentar a contagem e o processo aguardando o semáforo verifica novamente e, quando vê o recurso disponível, diminui a contagem novamente. Portanto, em termos de semáforo binário, apenas o processo que contém o semáforo pode aumentar a contagem, e a contagem permanece zero até que ele pare de usar o semáforo e aumente a contagem e outro processo tenha a chance de acessar o semáforo.

A principal diferença entre o semáforo binário e o mutex é que o semáforo é um mecanismo de sinalização e o mutex é um mecanismo de bloqueio, mas o semáforo binário parece funcionar como o mutex que cria confusão, mas ambos são conceitos diferentes, adequados para diferentes tipos de trabalho.

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.