Un sémaphore est un concept de programmation fréquemment utilisé pour résoudre des problèmes de multi-threading. Ma question à la communauté:
Qu'est-ce qu'un sémaphore et comment l'utilisez-vous?
multithreading
concurrency
semaphore
bmurphy1976
la source
la source
Réponses:
Considérez les sémaphores comme des videurs dans une boîte de nuit. Il y a un nombre dédié de personnes autorisées à la fois dans le club. Si le club est plein, personne n'est autorisé à entrer, mais dès qu'une personne quitte, une autre peut entrer.
C'est simplement un moyen de limiter le nombre de consommateurs pour une ressource spécifique. Par exemple, pour limiter le nombre d'appels simultanés à une base de données dans une application.
Voici un exemple très pédagogique en C # :-)
la source
L'article Mutexes and Semaphores Demystified by Michael Barr est une excellente introduction courte sur ce qui rend les mutexes et les sémaphores différents, et quand ils doivent et ne doivent pas être utilisés. J'ai extrait plusieurs paragraphes clés ici.
Le point clé est que les mutex devraient être utilisés pour protéger les ressources partagées, tandis que les sémaphores devraient être utilisés pour la signalisation. Vous ne devez généralement pas utiliser de sémaphores pour protéger les ressources partagées, ni de mutex pour la signalisation. Il y a des problèmes, par exemple, avec l'analogie du videur en termes d'utilisation de sémaphores pour protéger les ressources partagées - vous pouvez les utiliser de cette façon, mais cela peut rendre difficile le diagnostic des bogues.
...
À ce stade, une analogie intéressante est faite en utilisant l'idée des clés de la salle de bain comme protection des ressources partagées - la salle de bain. Si un magasin n'a qu'une seule salle de bain, une seule clé sera suffisante pour protéger cette ressource et empêcher plusieurs personnes de l'utiliser simultanément.
S'il y a plusieurs salles de bains, on pourrait être tenté de les saisir de la même manière et de créer plusieurs clés - cela ressemble à un sémaphore mal utilisé. Une fois que vous avez une clé, vous ne savez pas vraiment quelle salle de bain est disponible, et si vous suivez cette voie, vous finirez probablement par utiliser des mutex pour fournir ces informations et vous assurer de ne pas prendre une salle de bain déjà occupée. .
Un sémaphore n'est pas le bon outil pour protéger plusieurs des mêmes ressources, mais c'est le nombre de personnes qui y pensent et l'utilisent. L'analogie du videur est distinctement différente - il n'y a pas plusieurs du même type de ressource, au lieu de cela il y a une ressource qui peut accepter plusieurs utilisateurs simultanés. Je suppose qu'un sémaphore peut être utilisé dans de telles situations, mais il y a rarement des situations réelles où l'analogie tient réellement - c'est plus souvent qu'il y en a plusieurs du même type, mais toujours des ressources individuelles, comme les salles de bains, qui ne peuvent pas être utilisées par ici.
...
...
Ici, il est important de noter que les mutex interfèrent mal avec les systèmes d'exploitation en temps réel, provoquant une inversion de priorité où une tâche moins importante peut être exécutée avant une tâche plus importante en raison du partage des ressources. En bref, cela se produit lorsqu'une tâche de priorité inférieure utilise un mutex pour récupérer une ressource, A, puis tente de récupérer B, mais est interrompue car B n'est pas disponible. Pendant qu'il attend, une tâche de priorité plus élevée survient et nécessite A, mais elle est déjà bloquée, et par un processus qui n'est même pas en cours d'exécution car il attend B. Il existe de nombreuses façons de résoudre ce problème, mais le plus souvent il est corrigé en modifiant le mutex et le gestionnaire de tâches. Le mutex est beaucoup plus complexe dans ces cas qu'un sémaphore binaire,
...
Mutex: partage de ressources
Sémaphore: signalisation
N'utilisez pas l'un pour l'autre sans avoir soigneusement pris en compte les effets secondaires.
la source
Mutex: accès exclusif des membres à une ressource
Sémaphore: accès de n membres à une ressource
Autrement dit, un mutex peut être utilisé pour synchroniser l'accès à un compteur, un fichier, une base de données, etc.
Un sempahore peut faire la même chose mais prend en charge un nombre fixe d'appels simultanés. Par exemple, je peux encapsuler mes appels de base de données dans un sémaphore (3) afin que mon application multithread atteigne la base de données avec au plus 3 connexions simultanées. Toutes les tentatives seront bloquées jusqu'à ce que l'un des trois emplacements s'ouvre. Ils font des choses comme faire de la limitation naïve vraiment, vraiment facile.
la source
Considérez, un taxi qui peut accueillir un total de 3 ( arrière ) +2 ( avant ) personnes, y compris le chauffeur. Ainsi, un
semaphore
autorise seulement 5 personnes à l'intérieur d'une voiture à la fois. Et unmutex
permet une seule personne sur un seul siège de la voiture.Par conséquent,
Mutex
est d'autoriser l'accès exclusif à une ressource ( comme un thread OS ) tandis que aSemaphore
est d'autoriser l'accès à n nombre de ressources à la fois.la source
@Craig:
Ce n'est pas limité à un seul thread. Un sémaphore peut être configuré pour permettre à un nombre fixe de threads d'accéder à une ressource.
la source
Le sémaphore peut également être utilisé comme ... sémaphore. Par exemple, si vous avez plusieurs processus de mise en file d'attente de données dans une file d'attente et une seule tâche consommant des données de la file d'attente. Si vous ne voulez pas que votre tâche consommatrice interroge constamment la file d'attente pour les données disponibles, vous pouvez utiliser le sémaphore.
Ici, le sémaphore n'est pas utilisé comme mécanisme d'exclusion, mais comme mécanisme de signalisation. La tâche consommatrice attend sur le sémaphore La tâche productrice est en cours de publication sur le sémaphore.
De cette façon, la tâche consommatrice s'exécute quand et seulement lorsqu'il y a des données à retirer de la file d'attente
la source
Il existe deux concepts essentiels à la création de programmes simultanés: la synchronisation et l'exclusion mutuelle. Nous verrons comment ces deux types de verrous (les sémaphores sont plus généralement une sorte de mécanisme de verrouillage) nous aident à réaliser la synchronisation et l'exclusion mutuelle.
Un sémaphore est une construction de programmation qui nous aide à atteindre la concurrence, en implémentant à la fois la synchronisation et l'exclusion mutuelle. Les sémaphores sont de deux types, binaire et comptage.
Un sémaphore se compose de deux parties: un compteur et une liste de tâches en attente d'accès à une ressource particulière. Un sémaphore effectue deux opérations: attendre (P) [c'est comme acquérir un verrou], et relâcher (V) [similaire à libérer un verrou] - ce sont les deux seules opérations que l'on peut effectuer sur un sémaphore. Dans un sémaphore binaire, le compteur va logiquement entre 0 et 1. Vous pouvez le considérer comme étant similaire à un verrou avec deux valeurs: ouvert / fermé. Un sémaphore de comptage a plusieurs valeurs pour le comptage.
Ce qui est important à comprendre, c'est que le compteur de sémaphores garde une trace du nombre de tâches qui n'ont pas à bloquer, c'est-à-dire qu'elles peuvent progresser. Les tâches se bloquent et ne s'ajoutent à la liste du sémaphore que lorsque le compteur est nul. Par conséquent, une tâche est ajoutée à la liste dans la routine P () si elle ne peut pas progresser et "libérée" à l'aide de la routine V ().
Maintenant, il est assez évident de voir comment les sémaphores binaires peuvent être utilisés pour résoudre la synchronisation et l'exclusion mutuelle - ce sont essentiellement des verrous.
ex. Synchronisation:
Dans l'exemple ci-dessus, B2 ne peut s'exécuter qu'une fois que B1 a terminé son exécution. Disons que le thread A vient s'exécute en premier - arrive à sem.P (), et attend, puisque le compteur est 0 (fermé). Le fil B arrive, termine B1, puis libère le fil A - qui termine ensuite B2. Nous réalisons donc la synchronisation.
Examinons maintenant l'exclusion mutuelle avec un sémaphore binaire:
L'exclusion mutuelle est également assez simple - m1 et m2 ne peuvent pas entrer en même temps dans la section critique. Ainsi, chaque thread utilise le même sémaphore pour fournir une exclusion mutuelle pour ses deux sections critiques. Maintenant, est-il possible d'avoir une plus grande simultanéité? Dépend des sections critiques. (Réfléchissez à la façon dont on pourrait utiliser les sémaphores pour parvenir à l'exclusion mutuelle. Indice indice: ai-je nécessairement seulement besoin d'utiliser un seul sémaphore?)
Sémaphore de comptage: un sémaphore avec plus d'une valeur. Voyons ce que cela implique - un verrou avec plus d'une valeur ?? Donc ouvert, fermé et ... hmm. À quoi sert un verrouillage à plusieurs étages dans l'exclusion mutuelle ou la synchronisation?
Prenons le plus simple des deux:
Synchronisation à l'aide d'un sémaphore de comptage: Disons que vous avez 3 tâches - n ° 1 et 2 que vous souhaitez exécuter après 3. Comment concevriez-vous votre synchronisation?
Donc, si votre sémaphore commence fermé, vous vous assurez que les blocs t1 et t2 soient ajoutés à la liste des sémaphores. Vient ensuite tout le t3 important, termine son activité et libère le t1 et le t2. Dans quel ordre sont-ils libérés? Dépend de l'implémentation de la liste des sémaphores. Pourrait être FIFO, pourrait être basé sur une priorité particulière, etc. (Remarque: réfléchissez à la façon dont vous organiseriez vos P et V; si vous vouliez que t1 et t2 soient exécutés dans un ordre particulier et si vous n'étiez pas au courant de l'implémentation du sémaphore)
(Découvrez: que se passe-t-il si le nombre de V est supérieur au nombre de P?)
Exclusion mutuelle à l'aide de sémaphores de comptage: j'aimerais que vous construisiez votre propre pseudocode pour cela (vous fait mieux comprendre les choses!) - mais le concept fondamental est le suivant: un sémaphore de comptage de compteur = N permet à N tâches d'entrer librement dans la section critique . Cela signifie que vous avez N tâches (ou threads, si vous le souhaitez) entrez dans la section critique, mais la tâche N + 1 est bloquée (va sur notre liste de tâches bloquées préférée), et n'est autorisée que lorsque quelqu'un V est le sémaphore au moins une fois. Ainsi, le compteur de sémaphores, au lieu de basculer entre 0 et 1, va maintenant entre 0 et N, permettant à N tâches d'entrer et de sortir librement, ne bloquant personne!
Maintenant mon Dieu, pourquoi auriez-vous besoin d'une chose aussi stupide? N'est-ce pas tout l'intérêt de l'exclusion mutuelle de ne pas laisser plus d'un mec accéder à une ressource ?? (Astuce Astuce ... Vous n'avez pas toujours qu'un seul lecteur dans votre ordinateur, n'est-ce pas ...?)
Réfléchir : L'exclusion mutuelle est-elle obtenue en ayant un sémaphore de comptage seul? Que se passe-t-il si vous disposez de 10 instances d'une ressource et que 10 threads entrent (via le sémaphore de comptage) et tentent d'utiliser la première instance?
la source
Un sémaphore est un objet contenant un nombre naturel (c'est-à-dire un entier supérieur ou égal à zéro) sur lequel deux opérations de modification sont définies. Une opération,
V
ajoute 1 au naturel. L'autre opérationP
,, diminue le nombre naturel de 1. Les deux activités sont atomiques (c'est-à-dire qu'aucune autre opération ne peut être exécutée en même temps que aV
ou aP
).Parce que le nombre naturel 0 ne peut pas être diminué, l'appel
P
à un sémaphore contenant un 0 bloquera l'exécution du processus appelant (/ thread) jusqu'à un certain moment où le nombre n'est plus 0 etP
peut être exécuté avec succès (et atomiquement).Comme mentionné dans d'autres réponses, les sémaphores peuvent être utilisés pour restreindre l'accès à une certaine ressource à un nombre maximum (mais variable) de processus.
la source
J'ai créé la visualisation qui devrait aider à comprendre l'idée. Le sémaphore contrôle l'accès à une ressource commune dans un environnement multithreading.
Production
Exemple de code de l' article
la source
Un indicateur matériel ou logiciel. Dans les systèmes multitâches, un sémaphore est une variable avec une valeur qui indique l'état d'une ressource commune. Un processus qui a besoin de la ressource vérifie le sémaphore pour déterminer l'état des ressources, puis décide de la marche à suivre.
la source
Les sémaphores agissent comme des limiteurs de threads.
Exemple: si vous disposez d'un pool de 100 threads et que vous souhaitez effectuer une opération de base de données. Si 100 threads accèdent à la base de données à un moment donné, il peut y avoir un problème de verrouillage dans la base de données afin que nous puissions utiliser un sémaphore qui n'autorise qu'un nombre limité de threads à la fois. L'exemple ci-dessous autorise un seul thread à la fois. Lorsqu'un thread appelle le
acquire()
méthode, il obtient alors l'accès et après avoir appelé lerelease()
méthode, il libérera l'accès afin que le thread suivant obtienne l'accès.la source
Imaginez donc que tout le monde essaie d'aller aux toilettes et qu'il n'y ait qu'un certain nombre de clés pour la salle de bain. S'il ne reste plus assez de clés, cette personne doit attendre. Considérez donc le sémaphore comme représentant l'ensemble de clés disponibles pour les salles de bains (les ressources du système) auxquelles différents processus (les amateurs de salles de bains) peuvent demander l'accès.
Imaginez maintenant deux processus essayant d'aller aux toilettes en même temps. Ce n'est pas une bonne situation et des sémaphores sont utilisés pour empêcher cela. Malheureusement, le sémaphore est un mécanisme volontaire et les processus (nos amateurs de salle de bain) peuvent l'ignorer (c'est-à-dire que même s'il y a des clés, quelqu'un peut toujours ouvrir la porte).
Il existe également des différences entre les sémaphores binaires / mutex et de comptage.
Consultez les notes de cours sur http://www.cs.columbia.edu/~jae/4118/lect/L05-ipc.html .
la source
C'est une vieille question mais l'une des utilisations les plus intéressantes du sémaphore est un verrou en lecture / écriture et il n'a pas été explicitement mentionné.
Les verrous r / w fonctionnent de façon simple: consommez un permis pour un lecteur et tous les permis pour des écrivains. En effet, une implémentation triviale du verrou ar / w mais nécessite une modification des métadonnées à la lecture (en fait deux fois) qui peut devenir un goulot d'étranglement, encore nettement mieux qu'un mutex ou un verrou.
Un autre inconvénient est que les écrivains peuvent également être démarrés assez facilement à moins que le sémaphore soit juste ou que les écritures n'obtiennent des permis dans plusieurs demandes, dans ce cas, elles ont besoin d'un mutex explicite entre elles.
En outre lecture :
la source
Un sémaphore est un moyen de verrouiller une ressource afin qu'il soit garanti que pendant l'exécution d'un morceau de code, seul ce morceau de code a accès à cette ressource. Cela empêche deux threads d'accéder simultanément à une ressource, ce qui peut provoquer des problèmes.
la source