Dans quelle situation utilisez-vous un sémaphore sur un mutex en C++?

tout au long des ressources que j'ai lues sur le multithreading, mutex est plus souvent utilisé et discuté par rapport à un sémaphore. Ma question est quand utilisez-vous un sémaphore sur un mutex? Je ne vois pas de sémaphore dans le fil de renforcement. Cela signifie-t-il que les sémaphores n'utilisent plus beaucoup ces jours-ci?

autant que je sache, les sémaphores permettent à une ressource d'être partagée par plusieurs threads. Ceci n'est possible que si ces threads sont seulement en train de lire la ressource mais pas en train d'écrire. Être ce correct?

34
demandé sur jasonline 2010-02-28 11:47:44

9 réponses

coup de pouce.Le Thread a des mutex et des variables de condition. Purement en termes de fonctionnalité, les sémaphores sont donc redondants [*], bien que je ne sache pas si c'est la raison pour laquelle ils sont omis.

Les sémaphores

sont une primitive plus basique, plus simple, et peut-être implémentée pour être plus rapide, mais n'ont pas priorité-évitement des inversions. Ils sont sans doute plus difficiles à utiliser que les variables de condition, car ils nécessitent le code client pour s'assurer que le nombre de messages "correspond" au nombre des temps d'attente dans certains de manière appropriée. Avec les variables de condition, il est facile de tolérer les messages parasites, parce que personne en fait ne quoi que ce soit sans vérifier la condition.

Lire vs écrire des ressources est un leurre de l'OMI, il n'a rien à voir avec la différence entre un mutex et sémaphore. Si vous utilisez un sémaphore de comptage, vous pourriez avoir une situation où plusieurs threads accèdent simultanément à la même ressource, auquel cas il serait sans doute à un accès en lecture seule. Dans cette situation, vous pourriez être en mesure d'utiliser shared_mutex de Boost.Fil à la place. Mais les sémaphores ne sont pas" pour "protéger les ressources comme le sont les Mutex, ils sont" pour " envoyer un signal d'un fil à l'autre. Il est possible de utiliser pour contrôler l'accès à une ressource.

cela ne signifie pas que toutes les utilisations de sémaphores doivent se rapporter à des ressources en lecture seule. Par exemple, vous pouvez utiliser un sémaphore binaire à protéger une ressource en lecture/écriture. Peut-être pas une bonne idée, cependant, car un mutex vous donne souvent un meilleur comportement de planification.

[ * ] voici à peu près comment mettre en œuvre un sémaphore de comptage à l'aide d'un mutex et d'une variable de condition. Pour mettre en œuvre un sémaphore partagé, bien sûr, vous avez besoin d'un mutex/condvar partagé:

struct sem {
    mutex m;
    condvar cv;
    unsigned int count;
};

sem_init(s, value)
    mutex_init(s.m);
    condvar_init(s.cv);
    count = value;

sem_wait(s)
    mutex_lock(s.m);
    while (s.count <= 0) {
        condvar_wait(s.cv, s.m);
    }
    --s.count;
    mutex_unlock(s.m);

sem_post(s)
    mutex_lock(s.m);
    ++s.count;
    condvar_broadcast(s.cv)
    mutex_unlock(s.m);

donc, tout ce que vous pouvez faire avec les sémaphores, vous pouvez le faire avec les mutex et les variables de condition. Pas nécessairement par la mise en œuvre d'un sémaphore.

4
répondu Steve Jessop 2010-03-01 10:35:46

Le cas d'utilisation typique d'un mutex (permettant à un seul thread d'accès à une ressource à tout moment) est beaucoup plus fréquente que l'on utilise si un sémaphore. Mais un sémaphore est en fait le concept plus général: Un mutex est (presque) un cas particulier d'un sémaphore.

applications typiques seraient: Vous ne voulez pas créer plus de (par exemple) 5 connexions de base de données. Peu importe le nombre de fils ouvriers, ils doivent partager ces 5 connexions. Ou, si vous exécutez sur un N-core machine, vous pourriez vouloir s'assurer que certaines tâches de CPU/Mémoire intensive ne tournent pas dans plus de n threads en même temps (parce que cela réduirait seulement le débit dû aux commutateurs de contexte et aux effets de cache thrashing). Vous pourriez même vouloir limiter le nombre de tâches CPU/Mémoire intensives en parallèle à N-1, de sorte que le reste du système ne meurt pas de faim. Ou imaginez qu'une certaine tâche nécessite beaucoup de mémoire, donc exécuter plus de N exemples de cette tâche en même temps conduirait à un bippage. Vous pourrait utiliser un sémaphore ici, pour s'assurer que pas plus de N exemples de cette tâche particulière courir en même temps.

EDIT/PS: à Partir de votre question "Ceci n'est possible que si les discussions ne sont que la lecture de la ressource, mais pas l'écriture. Est-ce correct?"et votre commentaire, il me semble que vous pensez à une ressource comme une variable ou un flux, qui peut être lu ou écrit et qui ne peut être écrit que par un fil à la fois. Ne le fais pas. Cela est trompeur dans ce cadre.

Pensez à des ressources comme l'eau. Vous pouvez utiliser de l'eau pour laver votre vaisselle. Je peux utiliser de l'eau pour laver ma vaisselle en même temps. Nous n'avons pas besoin de synchronisation pour cela, parce qu'il y a assez d'eau pour nous deux. Nous n'utilisons pas nécessairement la même eau . (Et vous ne pouvez pas "lu" ou "écriture" de l'eau.) Mais le de la quantité totale de l'eau est fini . Donc ce n'est pas possible pour n'importe quel nombre de parties pour laver leur vaisselle en même temps. Ce genre de synchronisation se fait avec un sémaphore. Seulement généralement pas avec de l'eau mais avec d'autres ressources finies comme la mémoire, l'espace disque, le débit IO ou les cœurs CPU.

18
répondu Niki 2010-02-28 09:38:57

l'essence de La différence entre un mutex et sémaphore a à voir avec la notion de propriété. Quand un mutex est pris, nous pensons que ce fil possède le mutex et que ce même fil doit ensuite libérer le mutex pour libérer la ressource.

pour un sémaphore, pensez à prendre le sémaphore comme consommant la ressource, mais pas réellement en prendre possession. Ceci est généralement appelé le sémaphore étant "vide" plutôt que possédé par un fil. La caractéristique du sémaphore est alors qu'un fil différent peut "remplir" le sémaphore de nouveau à l'état "complet".

par conséquent, les mutex sont généralement utilisés pour la protection de la concurrence des ressources (exlusion mutuelle) tandis que les sémaphores sont utilisés pour la signalisation entre les fils (comme les drapeaux de sémaphore signalant entre les navires). Un mutex en lui-même ne peut pas vraiment être utilisé pour la signalisation, mais les sémaphores le peuvent. Ainsi, en sélectionnant l'un sur l'autre dépend de ce que vous essayez de faire.

Voir un autre un de mes réponses ici pour plus de discussion sur un sujet connexe, couvrant la distinction entre récursives et non récursives mutex.

11
répondu Tall Jeff 2017-05-23 12:31:52

pour contrôler l'accès À un nombre limité de ressources partagées par plusieurs threads (inter - ou intra-processus).

dans notre application, nous avions une ressource très lourde et que nous ne voulions pas allouer un pour chacun des fils ouvriers. Comme un travailleur avait besoin de la ressource pour une petite partie de son travail, nous utilisions rarement plus que quelques ressources simultanément.

ainsi, nous avons alloué N de ceux quand plus de n threads essayaient d'utiliser la ressource, ils se contentaient de la bloquer jusqu'à ce qu'elle soit disponible.

9
répondu R Samuel Klatchko 2010-02-28 16:13:56

j'ai l'impression qu'il n'y a pas de façon simple de vraiment répondre à votre question sans négliger certaines informations importantes sur les sémaphores. Les gens ont écrit beaucoup de livres sur les sémaphores , de sorte que n'importe un ou deux paragraphes réponse est un mauvais service. Un livre populaire est Le Petit Livre de sémaphores ... pour ceux qui n'aiment pas les gros livres :).

voici un bon long article qui va dans beaucoup de détails sur la façon dont les sémaphores sont utilisés et comment ils sont destinés à être utilisés.

mise à jour:

Dan a souligné quelques erreurs dans mes exemples, je vais le laisser avec les références qui offrent de bien meilleures explications que les miennes :).

Voici les références montrant la bonne façon d'utiliser un sémaphore:

1. IBM Article

2. Conférence de classe de L'Université de Chicago

3. L'article de Netrino I affiché à l'origine.

4. Le "vendre des billets" papier + code.

3
répondu Kiril 2010-02-28 18:58:34

tel que repris de cet article :

un mutex permet la synchronisation inter-processus. Si vous instanciez un mutex avec un nom (comme dans le code ci-dessus), le mutex devient systémique. C'est vraiment utile si vous partagez la même bibliothèque entre de nombreuses applications différentes et avez besoin de bloquer l'accès à une section critique de code qui est d'accéder à des ressources qui ne peuvent pas être partagées.

enfin, le cours de sémaphore. Disons que vous avez une méthode qui est vraiment intensive en CPU, et qui utilise aussi des ressources dont vous avez besoin pour contrôler l'accès à (en utilisant des Mutex :)). Vous avez également déterminé qu'un maximum de cinq appels à la méthode est à peu près tout votre machine peut hanlde sans le rendre insensible. Votre meilleure solution ici est d'utiliser le Sémaphore de la classe qui permet de limiter un certain nombre de threads' accès à une ressource.

1
répondu Kane 2010-02-28 10:40:54

d'après ce que j'ai compris, sémaphore est un terme fortement lié à la CIB de nos jours. Il signifie encore variable protégée de nombreux processus peuvent modifier, mais parmi les processus et cette fonctionnalité est prise en charge par OS.

Habituellement, nous n'avons pas besoin d'une variable et un simple mutex couvrent tous nos besoins. Si nous avons encore besoin d'une variable, probablement, nous la codons nous - mêmes - "variable + mutex" pour obtenir plus de contrôle.

résumé: nous n'utilisons pas de sémaphores en multithreading parce que généralement utiliser mutex pour la simplicité et le contrôle, et nous utilisons des sémaphores pour la CIB parce que C'est OS-pris en charge et un nom officiel pour le mécanisme de synchronisation des processus.

0
répondu seas 2010-02-28 09:28:49

sémaphores a été conçu à l'origine pour la synchronisation entre les processus. Windows utilise WaitForMultipleObjects qui est comme un sémaphore. Dans le monde linux, l'implémentation initiale de pthread ne permettait pas de partager un mutex entre les processus. Maintenant ils le font. Le concept de briser l'incrément atomique (incrément enchevêtré dans les fenêtres) avec le mutex léger est la mise en œuvre la plus pratique ces jours-ci après threads est devenu l'Unité de planification pour le cpu. Si l'incrément et le lock étaient ensemble (sémaphore), le temps d'acquérir / libération des serrures sera trop long et nous ne pouvons pas diviser ces 2 fonctions d'unité comme nous le faisons aujourd'hui pour la performance et de meilleures constructions de synchronisation.

0
répondu MRN 2015-01-20 17:22:35

D'après ce que j'ai appris sur les sémaphores et les mutex à l'université, les sémaphores sont des objets plus théoriques tandis que les mutex sont une implémentation des sémaphores. Cela étant, les sémaphores sont plus souples.

Les Mutex

sont fortement dépendants de la mise en œuvre. Ils ont été optimisés pour leur fonction de verrouillage binaire. L'utilisation normale de cas d'un mutex est un sémaphore binaire.

en général, lorsque vous essayez d'écrire du code multithread sans bogue, la simplicité permet de. Les Mutex sont plus utilisés parce que leur simplicité permet d'éviter les scénarios d'impasse complexes qui découlent de l'utilisation de sémaphores.

-1
répondu Kousha 2010-02-28 10:51:44