Quand devrions-nous utiliser mutex et quand devrions-nous utiliser sémaphore

Réponses:

93

Voici comment je me souviens quand utiliser quoi -

Sémaphore: utilisez un sémaphore lorsque vous (thread) voulez dormir jusqu'à ce qu'un autre thread vous dise de vous réveiller. Le sémaphore `` down '' se produit dans un thread (producteur) et le sémaphore `` up '' (pour le même sémaphore) se produit dans un autre thread (consommateur), par exemple: dans un problème producteur-consommateur, le producteur veut dormir jusqu'à ce qu'au moins un emplacement de tampon soit vide - seulement le thread consommateur peut dire quand un emplacement de tampon est vide.

Mutex: utilisez un mutex lorsque vous (thread) souhaitez exécuter du code qui ne doit pas être exécuté par un autre thread en même temps. Mutex «down» se produit dans un thread et le mutex «up» doit se produire dans le même thread plus tard. Par exemple: si vous supprimez un nœud d'une liste chaînée globale, vous ne voulez pas qu'un autre thread se moque des pointeurs pendant que vous supprimez le nœud. Lorsque vous acquérez un mutex et êtes occupé à supprimer un nœud, si un autre thread essaie d'acquérir le même mutex, il sera mis en veille jusqu'à ce que vous libériez le mutex.

Spinlock: utilisez un spinlock lorsque vous voulez vraiment utiliser un mutex mais que votre thread n'est pas autorisé à dormir. Par exemple: un gestionnaire d'interruption dans le noyau du système d'exploitation ne doit jamais dormir. Si tel est le cas, le système se fige / plante. Si vous avez besoin d'insérer un nœud dans une liste chaînée partagée globalement à partir du gestionnaire d'interruption, obtenez un verrou tournant - insérer un nœud - verrouiller la libération.

Annu Gogatya
la source
1
à ajouter: les sémaphores et le mutex sont deux façons d'assurer la synchronisation. sémaphore, peut être davantage lié à la signalisation (par exemple, scénario de problème de producteur et de consommateur), et mutex, peut être davantage lié à l'autorisation d'accès à un à la fois (plusieurs demandes d'accès à une ressource partagée, mais une seule accordée à la fois). [bel article: geeksforgeeks.org/mutex-vs-semaphore/]
parasrish
57

Un mutex est un objet d'exclusion mutuelle, similaire à un sémaphore mais qui n'autorise qu'un seul casier à la fois et dont les restrictions de propriété peuvent être plus strictes qu'un sémaphore.

Il peut être considéré comme équivalent à un sémaphore de comptage normal (avec un compte de un) et à l'exigence qu'il ne puisse être libéré que par le même thread qui l'a verrouillé (a) .

Un sémaphore, d'un autre côté, a un nombre arbitraire et peut être verrouillé par autant de casiers simultanément. Et il n'est peut-être pas nécessaire qu'il soit publié par le même thread qui l'a revendiqué (mais, sinon, vous devez suivre attentivement qui en est actuellement responsable, un peu comme la mémoire allouée).

Donc, si vous avez un certain nombre d'instances d'une ressource (disons trois lecteurs de bande), vous pouvez utiliser un sémaphore avec un nombre de 3. Notez que cela ne vous dit pas lequel de ces lecteurs de bande vous avez, juste que vous avez un certain nombre.

De plus, avec les sémaphores, il est possible pour un même casier de verrouiller plusieurs instances d'une ressource, comme pour une copie de bande à bande. Si vous avez une ressource (disons un emplacement mémoire que vous ne voulez pas corrompre), un mutex est plus approprié.

Les opérations équivalentes sont:

Counting semaphore          Mutual exclusion semaphore
--------------------------  --------------------------
  Claim/decrease (P)                  Lock
  Release/increase (V)                Unlock

A part: au cas où vous vous êtes déjà demandé les lettres bizarres utilisées pour revendiquer et publier des sémaphores, c'est parce que l'inventeur était néerlandais. Probeer te verlagen signifie essayer de diminuer tandis que verhogen signifie augmenter.


(a) ... ou il peut être considéré comme quelque chose de totalement distinct d'un sémaphore, qui peut être plus sûr étant donné leurs utilisations presque toujours différentes.

paxdiablo
la source
D'accord, je suis tombé sur un sémaphore binaire aussi. Quand devrions-nous avoir besoin d'entrer pour le sémaphore binaire et quand devrions-nous utiliser mutex?
Karthik Balaguru
Conceptuellement, un sémaphore binaire est un mutex et équivaut à un sémaphore normal avec un nombre unique. Il peut y avoir des différences dans les implémentations du concept telles que l'efficacité ou la propriété de la ressource (peut être libérée par quelqu'un d'autre que le demandeur, ce que je ne suis pas d'accord avec BTW - une ressource ne devrait être libérable que par le thread qui l'a revendiquée ).
paxdiablo
1
Une autre différence de mise en œuvre potentielle est le mutex récursif. Comme il n'y a qu'une seule ressource, un seul thread peut être autorisé à le verrouiller plusieurs fois (à condition qu'il le libère autant de fois). Ce n'est pas si facile avec une ressource à plusieurs instances, car vous ne savez peut-être pas si le thread souhaite réclamer à nouveau une autre instance ou la même instance.
paxdiablo
1
Ils résolvent un problème spécifique. Le fait que le problème qu'ils résolvent soient des gens qui ne font pas vraiment de mutex, ne devrait en aucun cas minimiser la solution :-)
paxdiablo
5
Un mutex est totalement différent d'un sémaphore binaire. Désolé mais cette définition est fausse
Peer Stritzinger
49

Il est très important de comprendre qu'un mutex n'est pas un sémaphore avec le compte 1!

C'est la raison pour laquelle il y a des choses comme les sémaphores binaires (qui sont en réalité des sémaphores avec un compte 1).

La différence entre un Mutex et un Binary-Semaphore est le principe de propriété:

Un mutex est acquis par une tâche et doit donc également être libéré par la même tâche. Cela permet de résoudre plusieurs problèmes avec les sémaphores binaires (version accidentelle, blocage récursif et inversion de priorité).

Attention: j'ai écrit «rend possible», si et comment ces problèmes sont résolus dépend de l'implémentation du système d'exploitation.

Comme le mutex doit être libéré par la même tâche, il n'est pas très bon pour la synchronisation des tâches. Mais s'ils sont combinés avec des variables de condition, vous obtenez des blocs de construction très puissants pour construire toutes sortes de primitives ipc.

Donc, ma recommandation est la suivante: si vous avez des mutex et des variables de condition correctement implémentés (comme avec les pthreads POSIX), utilisez-les.

N'utilisez les sémaphores que s'ils correspondent exactement au problème que vous essayez de résoudre, n'essayez pas de construire d'autres primitives (par exemple, des rw-locks à partir de sémaphores, utilisez des mutex et des variables de condition pour ceux-ci)

Il y a beaucoup de mutex et de sémaphores mal compris. La meilleure explication que j'ai trouvée jusqu'à présent est dans cet article en 3 parties:

Mutex vs sémaphores - Partie 1: Sémaphores

Mutex vs sémaphores - Partie 2: Le Mutex

Mutex vs sémaphores - Partie 3 (dernière partie): Problèmes d'exclusion mutuelle

Peer Stritzinger
la source
Les urls de ce site contiennent des caractères funky et ne fonctionnent donc pas ... Je travaille dessus
Peer Stritzinger
13

Bien que la réponse @opaxdiablo soit totalement correcte, je tiens à souligner que le scénario d'utilisation des deux choses est assez différent. Le mutex est utilisé pour empêcher des parties de code de s'exécuter simultanément, des sémaphores sont utilisés pour qu'un thread signale à un autre thread de s'exécuter.

/* 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

Le scénario du sémaphore est différent:

/* Task 1 - Producer */
sema_post(&sem);   // Send the signal

/* Task 2 - Consumer */
sema_wait(&sem);   // Wait for signal

Voir http://www.netrino.com/node/202 pour plus d'explications

Patrick Schlüter
la source
2
Vous avez raison. Même si vous utilisez un sémaphore avec un nombre de un, vous impliquez quelque chose sur ce que vous faites que si vous utilisiez un mutex.
Omnifariable
Je ne suis pas sûr d'être d'accord avec cela, bien que je ne sois pas en désaccord avec tant de véhémence que je vous déconseille :-) Vous dites que le modèle d'utilisation des sémaphores est de notifier les threads mais c'est exactement ce que font les mutex quand il y a un autre thread en attente dessus, et exactement ce que les sémaphores ne font pas quand il n'y a pas de threads sema_wait:-) À mon avis, ils concernent tous les deux des ressources et la notification transmise à d'autres threads est un effet secondaire (très important, en termes de performances) du protection.
paxdiablo
You say that the usage pattern of semaphores is to notify threadsUn point sur la notification des threads. Vous pouvez appeler en sem_posttoute sécurité depuis un gestionnaire de signaux ( pubs.opengroup.org/onlinepubs/009695399/functions/… ) mais il n'est pas recommandé d'appeler pthread_mutex_locket pthread_mutex_unlockdepuis des gestionnaires de signaux ( manpages.ubuntu.com/manpages/lucid/man3/… )
@paxdiablo: Il y a une différence majeure entre ce sémaphore binaire mutex est le maintien du nombre de références. Mutex ou vous pouvez dire que n'importe quel mutex conditionnel ne maintient aucun compte lié au verrou alors que sempahore l'utilise pour maintenir le compte. Donc sem_wait et sem_post maintiennent le décompte.
Prak
9

Voir «L'exemple des toilettes» - http://pheatt.emporia.edu/courses/2010/cs557f10/hand07/Mutex%20vs_%20Semaphore.htm :

Mutex:

Est la clé d'une toilette. Une personne peut avoir la clé - occuper les toilettes - à la fois. Une fois terminé, la personne donne (libère) la clé à la personne suivante dans la file d'attente.

Officiellement: "Les mutex sont généralement utilisés pour sérialiser l'accès à une section de code rentrant qui ne peut pas être exécutée simultanément par plusieurs threads. Un objet mutex n'autorise qu'un thread dans une section contrôlée, ce qui oblige les autres threads qui tentent d'accéder à cette section pour attendre que le premier thread ait quitté cette section. " Réf: Bibliothèque des développeurs Symbian

(Un mutex est en réalité un sémaphore de valeur 1.)

Sémaphore:

Est le nombre de clés de toilettes identiques gratuites. Exemple, disons que nous avons quatre toilettes avec des serrures et des clés identiques. Le nombre de sémaphores - le nombre de clés - est réglé sur 4 au début (les quatre toilettes sont gratuites), puis la valeur de comptage est décrémentée à mesure que les gens entrent. Si toutes les toilettes sont pleines, c'est-à-dire. il n'y a plus de clés libres, le nombre de sémaphores est de 0. Maintenant, quand eq. une personne quitte les toilettes, le sémaphore est augmenté à 1 (une clé gratuite) et donné à la personne suivante dans la file d'attente.

Officiellement: «Un sémaphore limite le nombre d'utilisateurs simultanés d'une ressource partagée à un nombre maximum. Les threads peuvent demander l'accès à la ressource (décrémentation du sémaphore) et signaler qu'ils ont fini d'utiliser la ressource (incrémentation du sémaphore). " Réf: Bibliothèque des développeurs Symbian

fornwall
la source
7

Essayer de ne pas paraître loufoque, mais je ne peux pas m'en empêcher.

Votre question devrait être quelle est la différence entre mutex et sémaphores? Et pour être plus précis, la question devrait être: «Quelle est la relation entre mutex et sémaphores?

(J'aurais ajouté cette question mais je suis sûr à 100% qu'un modérateur trop zélé la fermerait comme un doublon sans comprendre la différence entre la différence et la relation.)

Dans la terminologie des objets, nous pouvons observer que:

observation.1 Le sémaphore contient un mutex

observation.2 Mutex n'est pas un sémaphore et le sémaphore n'est pas un mutex.

Il y a des sémaphores qui agiront comme s'ils étaient des mutex, appelés sémaphores binaires, mais ils ne sont PAS des mutex.

Il y a un ingrédient spécial appelé Signalisation (posix utilise condition_variable pour ce nom), requis pour créer un sémaphore à partir d'un mutex. Considérez-le comme une source de notification. Si deux ou plusieurs threads sont abonnés à la même source de notification, il est alors possible de leur envoyer un message à ONE ou à ALL, pour se réveiller.

Il pourrait y avoir un ou plusieurs compteurs associés aux sémaphores, qui sont gardés par mutex. Le scénario le plus simple pour le sémaphore, il existe un seul compteur qui peut être 0 ou 1.

C'est là que la confusion se déverse comme une pluie de mousson.

Un sémaphore avec un compteur qui peut être 0 ou 1 n'est PAS un mutex.

Mutex a deux états (0,1) et une propriété (tâche). Le sémaphore a un mutex, des compteurs et une variable de condition.

Maintenant, utilisez votre imagination, et chaque combinaison d'utilisation du compteur et du moment du signal peut créer une sorte de sémaphore.

  1. Compteur unique avec valeur 0 ou 1 et signalant quand la valeur passe à 1 ET puis déverrouille l'un des gars en attente du signal == Sémaphore binaire

  2. Compteur unique avec une valeur de 0 à N et signalant lorsque la valeur passe à moins de N, et se verrouille / attend lorsque la valeur est N == Sémaphore de comptage

  3. Compteur unique avec une valeur de 0 à N et signalant lorsque la valeur passe à N, et se verrouille / attend lorsque les valeurs sont inférieures à N == Sémaphore de barrière (enfin, s'ils ne l'appellent pas, alors ils devraient.)

Passons maintenant à votre question, quand utiliser quoi. (OU plutôt correcte question version.3 quand utiliser mutex et quand utiliser sémaphore binaire, car il n'y a pas de comparaison avec le sémaphore non binaire.) Utilisez mutex lorsque 1. vous voulez un comportement personnalisé, qui n'est pas fourni par binaire sémaphore, comme les verrous rotatifs ou rapides ou récursifs. Vous pouvez généralement personnaliser les mutex avec des attributs, mais la personnalisation du sémaphore n'est rien d'autre que l'écriture d'un nouveau sémaphore. 2. vous voulez une primitive légère OU plus rapide

Utilisez des sémaphores, lorsque ce que vous voulez est exactement fourni par celui-ci.

Si vous ne comprenez pas ce qui est fourni par votre implémentation de binary-sémaphore, alors à mon humble avis, utilisez mutex.

Et enfin, lisez un livre plutôt que de vous fier uniquement à SO.

Ajeet Ganga
la source
5

Je pense que la question devrait être la différence entre mutex et sémaphore binaire.

Mutex = C'est un mécanisme de verrouillage de propriété, seul le thread qui acquiert le verrou peut libérer le verrou.

binary Semaphore = Il s'agit plus d'un mécanisme de signal, tout autre thread de priorité plus élevée si vous le souhaitez peut signaler et prendre le verrou.

Saurabh Sengar
la source
5

Mutex est de protéger la ressource partagée.
Le sémaphore est de distribuer les fils.

Mutex:
Imaginez qu'il y ait des billets à vendre. Nous pouvons simuler un cas où de nombreuses personnes achètent les billets en même temps: chaque personne est un fil pour acheter des billets. De toute évidence, nous devons utiliser le mutex pour protéger les tickets car c'est la ressource partagée.


Sémaphore:
imaginez que nous devons faire un calcul comme ci-dessous:

c = a + b;

De plus, nous avons besoin d'une fonction geta()pour calculer a, d'une fonction getb()pour calculer bet d'une fonction getc()pour faire le calcul c = a + b.

De toute évidence, nous ne pouvons pas faire le c = a + bsauf geta()et getb()avoir été terminé.
Si les trois fonctions sont trois threads, nous devons distribuer les trois 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);

Avec l'aide de sémaphores, le code ci - dessus peut vous assurer que t3ne fera pas son travail jusqu'à ce t1et t2ont fait leur travail.

En un mot, le sémaphore est de faire exécuter les threads comme un ordre logique alors que le mutex est de protéger la ressource partagée.
Donc ils ne sont PAS la même chose même si certaines personnes disent toujours que le mutex est un sémaphore spécial avec la valeur initiale 1. Vous pouvez dire comme ça aussi, mais notez qu'ils sont utilisés dans des cas différents. Ne remplacez pas l'un par l'autre même si vous pouvez le faire.

Yves
la source
La vente de billets en est un bel exemple. L'exemple de sémaphore est peu clair (pour moi en tout cas).
prière du
1
L'exemple de @prayagupd Semaphore est de créer des threads dans un certain ordre alors que la vente de tickets ne nécessite aucun ordre. S'il y a trois personnes: a, b et c. Lorsqu'ils viennent acheter des billets, nous ne nous soucions pas du tout de l'ordre d'achat des billets. Cependant, si nous faisons un tel calcul: x = getx(); y = gety(); z = x + y;pour une raison quelconque, nous utilisons trois threads pour faire les trois choses, maintenant l'ordre des threads est très important parce que nous ne pouvons pas faire à x + ymoins getxet getyavoir terminé. En un mot, le sémaphore est utilisé lorsque l'on se soucie de l'ordre d'exécution du multi-threading.
Yves
je t'ai eu. Cela ressemble à une barrière . Je peux dire que attendre jusqu'à ce que les threads xet ysoient terminés, puis calculer z = x + y. Je sais que java a CyclicBarrier. De plus, je ne suis pas sûr de pouvoir dire que mapreducec'est aussi un cas d'utilisation de sémaphore, car je ne peux pas reducetant que tout mapn'est pas terminé.
priagupd
@prayagupd Oui. Vous pouvez dire ça.
Yves
2

Toutes les réponses ci-dessus sont de bonne qualité, mais celle-ci est juste à mémoriser.Le nom Mutex est dérivé de mutuellement exclusif, vous êtes donc motivé à penser à un verrouillage mutex comme une exclusion mutuelle entre deux comme dans un seul à la fois, et si je possédé, vous ne pouvez l'avoir qu'après l'avoir publié. D'un autre côté, un tel cas n'existe pas pour Semaphore, c'est comme un feu de signalisation (ce que le mot sémaphore signifie également).

Nishant Sondhi
la source
1

Comme cela a été souligné, un sémaphore comptant un est la même chose qu'un sémaphore «binaire» qui est la même chose qu'un mutex.

Les principales choses pour lesquelles j'ai vu des sémaphores avec un nombre supérieur à un sont les situations de producteur / consommateur dans lesquelles vous avez une file d'attente d'une certaine taille fixe.

Vous avez alors deux sémaphores. Le premier sémaphore est initialement défini pour être le nombre d'éléments dans la file d'attente et le second sémaphore est mis à 0. Le producteur effectue une opération P sur le premier sémaphore, ajoute à la file d'attente. et effectue une opération V sur le second. Le consommateur effectue une opération P sur le second sémaphore, supprime de la file d'attente, puis effectue une opération V sur le premier.

De cette manière, le producteur est bloqué chaque fois qu'il remplit la file d'attente et le consommateur est bloqué chaque fois que la file d'attente est vide.

Très varié
la source
1

Un mutex est un cas particulier de sémaphore. Un sémaphore permet à plusieurs threads d'entrer dans la section critique. Lors de la création d'un sémaphore, vous définissez comment les threads sont autorisés dans la section critique. Bien entendu, votre code doit pouvoir gérer plusieurs accès à cette section critique.

Frode Akselsen
la source
-1

Le sémaphore binaire et le Mutex sont différents. Du point de vue du système d'exploitation, un sémaphore binaire et un sémaphore de comptage sont implémentés de la même manière et un sémaphore binaire peut avoir la valeur 0 ou 1.

Mutex -> Ne peut être utilisé que dans un seul et unique but d'exclusion mutuelle pour une section critique du code.

Sémaphore -> Peut être utilisé pour résoudre divers problèmes. Un sémaphore binaire peut être utilisé pour la signalisation et également résoudre le problème d'exclusion mutuelle. Lorsqu'il est initialisé à 0 , il résout le problème de signalisation et lorsqu'il est initialisé à 1 , il résout le problème d' exclusion mutuelle .

Lorsque le nombre de ressources est plus important et doit être synchronisé, nous pouvons utiliser un sémaphore de comptage.

Dans mon blog, j'ai discuté de ces sujets en détail.

https://designpatterns-oo-cplusplus.blogspot.com/2015/07/synchronization-primitives-mutex-and.html

Chiffons
la source