Quand devrions-nous utiliser mutex et quand devrions-nous utiliser sémaphore?
Quand devrions-nous utiliser mutex et quand devrions-nous utiliser sémaphore?
Réponses:
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.
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.
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
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
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.
You say that the usage pattern of semaphores is to notify threads
Un point sur la notification des threads. Vous pouvez appeler en sem_post
toute sécurité depuis un gestionnaire de signaux ( pubs.opengroup.org/onlinepubs/009695399/functions/… ) mais il n'est pas recommandé d'appeler pthread_mutex_lock
et pthread_mutex_unlock
depuis des gestionnaires de signaux ( manpages.ubuntu.com/manpages/lucid/man3/… )
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
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.
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
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
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.
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.
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 b
et d'une fonction getc()
pour faire le calcul c = a + b
.
De toute évidence, nous ne pouvons pas faire le c = a + b
sauf 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 t3
ne fera pas son travail jusqu'à ce t1
et t2
ont 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.
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 + y
moins getx
et gety
avoir terminé. En un mot, le sémaphore est utilisé lorsque l'on se soucie de l'ordre d'exécution du multi-threading.
x
et y
soient 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 mapreduce
c'est aussi un cas d'utilisation de sémaphore, car je ne peux pas reduce
tant que tout map
n'est pas terminé.
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).
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.
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.
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