Quand faut-il utiliser un sémaphore et quand utiliser une variable conditionnelle (CondVar)?
Réponses
Trop de publicités?Les verrous sont utilisés pour de l'exclusion mutuelle. Lorsque vous voulez vous assurer qu'un morceau de code est atomique, mettre un verrou autour de lui. Vous pourrait théoriquement utiliser un sémaphore binaire pour ce faire, mais c'est un cas spécial.
Les sémaphores et les variables de condition construire au-dessus de l'exclusion mutuelle fournir par les verrous et sont utilisés pour fournir un accès synchronisé aux ressources partagées. Ils peuvent être utilisés à des fins similaires.
Une variable de condition est généralement utilisé pour éviter occupé attente (en boucle à plusieurs reprises lors de la vérification d'une condition) lors de l'attente pour les ressources deviennent disponibles. Par exemple, si vous avez un thread (ou plusieurs threads) qui ne peut pas continuer en avant jusqu'à ce qu'une file d'attente est vide, le occupé attente approche serait de simplement faire quelque chose comme:
//pseudocode
while(!queue.empty())
{
sleep(1);
}
Le problème avec ceci est que vous gaspillez le temps de traitement en ayant ce fil de vérifier à plusieurs reprises l'état. Pourquoi ne pas plutôt avoir une synchronisation variable qui peut être signalé à dire le fil que la ressource est disponible?
//pseudocode
syncVar.lock.acquire();
while(!queue.empty())
{
syncVar.wait();
}
//do stuff with queue
syncVar.lock.release();
Sans doute, vous aurez un fil quelque part d'autre que de sortir les choses de la file d'attente. Lorsque la file d'attente est vide, il peut appeler syncVar.signal()
pour réveiller un thread au hasard qui est assis endormi sur syncVar.wait()
(ou il y a généralement aussi une signalAll()
ou broadcast()
de réveiller tous les threads en attente).
J'utilise généralement la synchronisation des variables de ce genre quand j'ai un ou plusieurs threads en attente sur une seule condition particulière (par exemple pour la file d'attente à vide).
Les sémaphores peuvent être utilisés de la même manière, mais je pense qu'ils sont mieux utilisé lorsque vous avez une ressource partagée qui peut être disponible et indisponible sur certains nombre entier nombre de choses. Les sémaphores sont bons pour producteur/consommateur situations où les producteurs sont l'allocation des ressources et les consommateurs sont de les consommer.
Pensez si vous aviez un distributeur de sodas. Il n'y a qu'une machine de soda et c'est une ressource partagée. Vous en avez un thread qui est un fournisseur (producteur), qui est responsable de maintenir la machine en stock et N threads qui sont les acheteurs (consommateurs) qui veulent obtenir des sodas de la machine. Le nombre de sodas dans la machine est la valeur de l'entier qui sera le moteur de notre sémaphore.
Chaque acheteur (consommateur) fil qui vient de la machine de soda appelle le sémaphore down()
méthode pour prendre une canette de soda. Cela permettra d'attraper une canette de soda de la machine et de réduire le nombre de disposition des sodas par 1. Si il y a des sodas sont disponibles, le code sera juste garder en cours d'exécution passé l' down()
déclaration sans problème. Si pas de boissons gazeuses sont disponibles, le thread va dormir ici en attente d'être notifié de soude est de nouveau disponibles (quand il y a plus de sodas dans la machine).
Le fournisseur (producteur) thread essentiellement dans l'attente de la machine de soda vide. Le vendeur est notifié lorsque le dernier de soude est prise à partir de la machine (et un ou plusieurs consommateurs sont potentiellement d'attente pour obtenir des sodas out). Le vendeur réapprovisionner la machine de soda avec le sémaphore up()
méthode, le nombre de sodas devrait être incrémenté à chaque fois et ainsi à l'attente des consommateurs fils averti que plus de soude est disponible.
L' wait()
et signal()
méthodes de synchronisation variable ont tendance à être caché à l'intérieur de l' down()
et up()
des opérations de sémaphore.
Certes il y a chevauchement entre les deux choix. Il existe de nombreux scénarios où un sémaphore ou d'une variable d'état (ou d'un ensemble de variables de condition) pourrait à la fois servir vos fins. Les deux sémaphores et les variables de condition sont associés avec un verrou de l'objet qu'ils utilisent pour maintenir l'exclusion mutuelle, mais ensuite, ils vous fournir des fonctionnalités supplémentaires sur le dessus de la serrure pour la synchronisation de l'exécution du thread. C'est surtout à vous de déterminer celui qui fait le plus de sens pour votre situation.
Ce n'est pas nécessairement la plus description technique, mais c'est comment il fait sens dans ma tête.
Les sémaphores peuvent être utilisés pour mettre en œuvre un accès exclusif à des variables, mais ils sont destinés à être utilisés pour la synchronisation. Mutex, d'autre part, ont une sémantique qui est strictement liée à l'exclusion mutuelle: seul le processus qui verrouille la ressource est autorisé à le déverrouiller.
Malheureusement, vous ne pouvez pas mettre en œuvre la synchronisation avec les mutex, c'est pourquoi nous avons des variables de condition. Notez également qu'avec les variables de condition, vous pouvez débloquer tous les threads en attente dans le même instant à l'aide de la diffusion de déverrouillage. Cela ne peut être fait avec des sémaphores.
Je fichier des variables de condition en vertu de surveiller la synchronisation. J'ai généralement vu les sémaphores et les moniteurs comme deux différents styles de synchronisation. Il y a des différences entre les deux en termes de la quantité de données d'état est intrinsèquement conservés et comment vous voulez le code du modèle - mais il n'y a vraiment pas de tout problème qui peut être résolu par l'un mais pas l'autre.
J'ai tendance à code vers le moniteur de forme; dans la plupart des langues, je travaille dans qui vient vers le bas pour les mutex, les variables de condition, et certains de la sauvegarde des variables d'état. Mais les sémaphores pour faire le travail aussi.