Qu'est-ce qu'un mutex?

655

Un mutex 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 mutex et comment l'utilisez-vous?

bmurphy1976
la source
2
Voici un bon article sur la différence: barrgroup.com/Embedded-Systems/How-To/RTOS-Mutex-Semaphore
Adam Davis
Un tutoriel sur mutex peut aider à clarifier les choses: stackoverflow.com/questions/4989451/mutex-example-tutorial
Nav
1
Un mutex est comme une clé de salle de bain dans une station-service, garantissant qu'une seule personne peut utiliser la salle de bain à la fois ET que personne d'autre ne peut utiliser les toilettes jusqu'à ce que l'occupant actuel ait terminé et que la clé soit retournée.
jonschlinkert

Réponses:

2154

Lorsque j'ai une grande discussion animée au travail, j'utilise un poulet en caoutchouc que je garde dans mon bureau pour de telles occasions. La personne qui tient le poulet est la seule personne autorisée à parler. Si vous ne tenez pas le poulet, vous ne pouvez pas parler. Vous pouvez seulement indiquer que vous voulez le poulet et attendre de l'avoir avant de parler. Une fois que vous avez fini de parler, vous pouvez remettre le poulet au modérateur qui le remettra à la prochaine personne à parler. Cela garantit que les gens ne se parlent pas entre eux et ont également leur propre espace pour parler.

Remplacez Poulet par Mutex et personne avec du fil et vous avez fondamentalement le concept d'un mutex.

Bien sûr, il n'existe pas de mutex en caoutchouc. Seulement poulet en caoutchouc. Mes chats avaient autrefois une souris en caoutchouc, mais ils l'ont mangée.

Bien sûr, avant d'utiliser le poulet en caoutchouc, vous devez vous demander si vous avez réellement besoin de 5 personnes dans une pièce et ne serait-il pas plus facile qu'une seule personne dans la pièce fasse tout le travail par elle-même. En fait, cela ne fait que prolonger l'analogie, mais vous avez l'idée.

Xetius
la source
9
Très bonne réponse. Peut-on affirmer que le Mutex est en fait les règles qui empêchent le poulet de passer? et le poulet est la chose que vous verrouillez?
SirYakalot
3
@SirYakalot, vous voulez dire que le poulet est la ressource et que le modérateur est le mutex?
Owen
158
Le poulet est le mutex . Les gens qui haïssent le poulet mu sont des fils concurrents . Le modérateur est l' OS . Lorsque les gens demandent le poulet, ils font une demande de verrouillage. Lorsque vous appelez mutex.lock (), votre thread se bloque dans lock () et fait une demande de verrouillage au système d'exploitation. Lorsque le système d'exploitation détecte que le mutex a été libéré d'un thread, il vous le donne simplement et lock () revient - le mutex est maintenant le vôtre et uniquement le vôtre. Personne d'autre ne peut le voler, car appeler lock () le bloquera. Il y a aussi try_lock () qui bloquera et retournera vrai quand mutex vous appartient et immédiatement faux si mutex est utilisé.
Петър Петров
4
Tu es un génie. Pouvez-vous également utiliser la métaphore du poulet en caoutchouc pour expliquer les moniteurs?
Riccardo
98
Parfois, l'origine de certains concepts de programmation n'est pas claire. Un débutant pourrait se demander pourquoi tout le monde parle de regex. Il n'est pas évident que l'expression régulière soit l'abréviation de [reg] ular [ex] pression. De même, mutex est l'abréviation de [mut] ual [ex] clusion. Cela pourrait rendre le sens du terme plus facile à digérer. @TheSmurf y est lié dans sa réponse, mais il pourrait être utile de l'ajouter ici à des fins historiques.
Dodzi Dzakuma
138

Un Mutex est un drapeau mutuellement exclusif. Il agit comme un gardien de porte à une section de code permettant un thread et bloquant l'accès à tous les autres. Cela garantit que le code contrôlé ne sera touché que par un seul thread à la fois. Assurez-vous simplement de libérer le mutex lorsque vous avez terminé. :)

Craig
la source
11
Un mutex n'a rien à voir avec une section de code en soi, il protège certaines ressources. Cette ressource peut être un segment de code si le mutex est uniquement utilisé autour de ce code mais, à la minute où vous commencez à utiliser le mutex à plusieurs endroits de votre code, votre explication échoue. En règle générale, il peut également être utilisé pour protéger une certaine structure de données, qui peut être consultée à de nombreux endroits dans le code.
paxdiablo
73

Exclusion mutuelle. Voici l'entrée Wikipedia à ce sujet:

http://en.wikipedia.org/wiki/Mutual_exclusion

Le but d'un mutex est de synchroniser deux threads. Lorsque vous avez deux threads tentant d'accéder à une seule ressource, le modèle général consiste à avoir le premier bloc de code tentant d'accéder à définir le mutex avant d'entrer le code. Lorsque le deuxième bloc de code tente d'accéder, il voit que le mutex est défini et attend que le premier bloc de code soit terminé (et dé-définit le mutex), puis continue.

Les détails spécifiques de la façon dont cela est accompli varient évidemment considérablement selon le langage de programmation.

Le Schtroumpf
la source
65

Lorsque vous disposez d'une application multithread, les différents threads partagent parfois une ressource commune, telle qu'une variable ou similaire. Cette source partagée est souvent inaccessible en même temps, donc une construction est nécessaire pour garantir qu'un seul thread utilise cette ressource à la fois.

Le concept est appelé "exclusion mutuelle" (Mutex court), et est un moyen de garantir qu'un seul thread est autorisé à l'intérieur de cette zone, en utilisant cette ressource, etc.

La façon de les utiliser est spécifique à la langue, mais est souvent (sinon toujours) basée sur un mutex de système d'exploitation.

Certains langages n'ont pas besoin de cette construction, en raison du paradigme, par exemple la programmation fonctionnelle (Haskell, ML sont de bons exemples).

Mats Fredriksson
la source
26

En C #, le mutex commun utilisé est le moniteur . Le type est ' System.Threading.Monitor '. Il peut également être utilisé implicitement via l' instruction ' lock (Object) '. Un exemple de son utilisation est lors de la construction d'une classe Singleton.

private static readonly Object instanceLock = new Object();
private static MySingleton instance;
public static MySingleton Instance
{
    lock(instanceLock)
    {
        if(instance == null)
        {
            instance = new MySingleton();
        }
        return instance;
    }
}

L'instruction lock utilisant l'objet lock privé crée une section critique. Obliger chaque thread à attendre la fin du précédent. Le premier thread entrera dans la section et initialisera l'instance. Le deuxième thread attendra, entrera dans la section et récupérera l'instance initialisée.

Toute sorte de synchronisation d'un membre statique peut utiliser l'instruction de verrouillage de la même manière.

Anthony Mastrean
la source
1
Il s'agit d'une réponse dépendante de l'implémentation. De plus, dans CS, un moniteur est différent de mutex. Les moniteurs ont un mécanisme de synchronisation mais mutex verrouille simplement la chose jusqu'à ce qu'elle ne soit plus nécessaire. IDK sur les détails d'implémentation ou la sémantique C #, mais je pense que le contexte de la question est plus large
marcoslhc
25

Qu'est-ce qu'un Mutex ?

Le mutex (en fait, le terme mutex est l'abréviation d'exclusion mutuelle) également connu sous le nom de spinlock est l'outil de synchronisation le plus simple utilisé pour protéger les régions critiques et ainsi empêcher les conditions de concurrence. C'est-à-dire qu'un thread doit acquérir un verrou avant d'entrer dans une section critique (dans une section critique, plusieurs threads partagent une variable commune, mettant à jour une table, écrivant un fichier, etc.), il libère le verrou lorsqu'il quitte la section critique.

Qu'est-ce qu'une condition de course ?

Une condition de concurrence critique se produit lorsque deux threads ou plus peuvent accéder aux données partagées et qu'ils essaient de les modifier en même temps. Étant donné que l'algorithme de planification des threads peut à tout moment basculer entre les threads, vous ne connaissez pas l'ordre dans lequel les threads tenteront d'accéder aux données partagées. Par conséquent, le résultat de la modification des données dépend de l'algorithme de programmation des threads, c'est-à-dire que les deux threads sont "en course" pour accéder / modifier les données.

Exemple réel:

Lorsque j'ai une grande discussion animée au travail, j'utilise un poulet en caoutchouc que je garde dans mon bureau pour de telles occasions. La personne qui tient le poulet est la seule personne autorisée à parler. Si vous ne tenez pas le poulet, vous ne pouvez pas parler. Vous pouvez seulement indiquer que vous voulez le poulet et attendre de l'avoir avant de parler. Une fois que vous avez fini de parler, vous pouvez remettre le poulet au modérateur qui le remettra à la prochaine personne à parler. Cela garantit que les gens ne se parlent pas entre eux et ont également leur propre espace pour parler.

Remplacez Poulet par Mutex et personne avec du fil et vous avez fondamentalement le concept d'un mutex.

@Xetius

Utilisation en C #:

Cet exemple montre comment un objet Mutex local est utilisé pour synchroniser l'accès à une ressource protégée. Étant donné que chaque thread appelant est bloqué jusqu'à ce qu'il acquière la propriété du mutex, il doit appeler la méthode ReleaseMutex pour libérer la propriété du thread.

using System;
using System.Threading;

class Example
{
    // Create a new Mutex. The creating thread does not own the mutex.
    private static Mutex mut = new Mutex();
    private const int numIterations = 1;
    private const int numThreads = 3;

    static void Main()
    {
        // Create the threads that will use the protected resource.
        for(int i = 0; i < numThreads; i++)
        {
            Thread newThread = new Thread(new ThreadStart(ThreadProc));
            newThread.Name = String.Format("Thread{0}", i + 1);
            newThread.Start();
        }

        // The main thread exits, but the application continues to
        // run until all foreground threads have exited.
    }

    private static void ThreadProc()
    {
        for(int i = 0; i < numIterations; i++)
        {
            UseResource();
        }
    }

    // This method represents a resource that must be synchronized
    // so that only one thread at a time can enter.
    private static void UseResource()
    {
        // Wait until it is safe to enter.
        Console.WriteLine("{0} is requesting the mutex", 
                          Thread.CurrentThread.Name);
        mut.WaitOne();

        Console.WriteLine("{0} has entered the protected area", 
                          Thread.CurrentThread.Name);

        // Place code to access non-reentrant resources here.

        // Simulate some work.
        Thread.Sleep(500);

        Console.WriteLine("{0} is leaving the protected area", 
            Thread.CurrentThread.Name);

        // Release the Mutex.
        mut.ReleaseMutex();
        Console.WriteLine("{0} has released the mutex", 
            Thread.CurrentThread.Name);
    }
}
// The example displays output like the following:
//       Thread1 is requesting the mutex
//       Thread2 is requesting the mutex
//       Thread1 has entered the protected area
//       Thread3 is requesting the mutex
//       Thread1 is leaving the protected area
//       Thread1 has released the mutex
//       Thread3 has entered the protected area
//       Thread3 is leaving the protected area
//       Thread3 has released the mutex
//       Thread2 has entered the protected area
//       Thread2 is leaving the protected area
//       Thread2 has released the mutex

Mutex de référence MSDN

habib
la source
1
un très bon exemple
Siwei Shen
22

Il y a quelques bonnes réponses ici, voici une autre grande analogie pour expliquer ce qu'est le mutex :

Pensez à des toilettes simples avec une clé . Quand quelqu'un entre, il prend la clé et les toilettes sont occupées . Si quelqu'un d'autre doit utiliser les toilettes, il doit attendre dans une file d'attente . Lorsque la personne aux toilettes a terminé , elle passe la clé à la personne suivante dans la file d'attente. C'est logique, non?

Convertissez les toilettes de l'histoire en une ressource partagée et la clé en un mutex . Prendre la clé des toilettes (acquérir une serrure) vous permet de l'utiliser. S'il n'y a pas de clé (la serrure est verrouillée), vous devez attendre. Lorsque la clé est rendue par la personne ( relâchez le verrou ), vous êtes libre de l'acquérir maintenant.

Chen A.
la source
Mais l'exemple c # ne prend pas en charge la prise en charge de votre affirmation de file d'attente, «passez la clé à la prochaine personne dans la file d'attente». L'exemple montre une pile ou aléatoire. 1, 2 et 3 demandent tous l'accès, dans cette séquence. Un est d'abord autorisé dans l'aire protégée, puis trois sont autorisés. Une file d'attente l'aurait donné au second.
donvnielsen
Je ne parlais d'aucune implémentation concrète ou langage de programmation concret. Mon exemple concerne l'abstraction de haut niveau du mutex comme principe.
Chen A.
18

Pour comprendre MUTEX au début, vous devez savoir ce qu'est une "condition de concurrence" et ensuite vous seul comprendrez pourquoi MUTEX est nécessaire. Supposons que vous ayez un programme multithread et que vous ayez deux threads. Maintenant, vous avez un travail dans la file d'attente des travaux. Le premier thread vérifiera la file d'attente des travaux et après avoir trouvé le travail, il commencera à l'exécuter. Le deuxième thread vérifiera également la file d'attente des travaux et trouvera qu'il y a un travail dans la file d'attente. Ainsi, il affectera également le même pointeur de tâche. Donc, maintenant ce qui se passe, les deux threads exécutent le même travail. Cela entraînera un défaut de segmentation. Ceci est l'exemple d'une condition de concurrence.

La solution à ce problème est MUTEX. MUTEX est une sorte de verrou qui verrouille un thread à la fois. Si un autre thread veut le verrouiller, le thread est simplement bloqué.

Le sujet MUTEX dans ce lien de fichier pdf vaut vraiment la peine d'être lu.

user3751012
la source
Par "sujet MUTEX", vous vouliez dire la section sur les sémaphores, parce que ses exemples sont des sémaphores binaires, non?
Carl G
2
un Mutex n'est qu'un sémaphore de valeur 1
marcoslhc
Quel est le nom du livre de ce chapitre que vous avez partagé? S'il vous plaît
Omar Faroque Anik
@OmarFaroqueAnik, le livre référencé est Advanced Linux Programming by CodeSourcery LLC, publié par New Riders Publishing et est accessible à partir de la page d'accueil du domaine lié.
RMart
11

Les mutex sont utiles dans les situations où vous devez appliquer un accès exclusif à une ressource sur plusieurs processus, où un verrou régulier n'aidera pas car il ne fonctionne que sur des threads.

18h
la source
Est-ce vraiment vrai? Les processus individuels ne créeront-ils pas leur propre copie mutex?
Leon
0

Mutex: Mutex signifie Mut ual Ex clusion. Cela signifie qu'à la fois un processus / thread peut entrer dans la section critique. Dans la programmation simultanée où plusieurs threads / processus essaient de mettre à jour la ressource partagée (n'importe quelle variable, mémoire partagée, etc.) peut entraîner un résultat inattendu. (Comme le résultat dépend du thread / processus qui obtient le premier accès).

Afin d'éviter un tel résultat inattendu, nous avons besoin d'un mécanisme de synchronisation, qui garantit qu'un seul thread / processus a accès à une telle ressource à la fois.

La bibliothèque pthread prend en charge Mutex.

typedef union
{
  struct __pthread_mutex_s
  {
    ***int __lock;***
    unsigned int __count;
    int __owner;
#ifdef __x86_64__
    unsigned int __nusers;
#endif
 int __kind;
#ifdef __x86_64__
    short __spins;
    short __elision;
    __pthread_list_t __list;
# define __PTHREAD_MUTEX_HAVE_PREV      1
# define __PTHREAD_SPINS             0, 0
#else
    unsigned int __nusers;
    __extension__ union
    {
      struct
      {
        short __espins;
        short __elision;
# define __spins __elision_data.__espins
# define __elision __elision_data.__elision
# define __PTHREAD_SPINS         { 0, 0 }
      } __elision_data;
      __pthread_slist_t __list;
    };
#endif

Il s'agit de la structure du type de données mutex, c'est-à-dire pthread_mutex_t. Lorsque mutex est verrouillé, __lock défini sur 1. Lorsqu'il est déverrouillé, __lock défini sur 0.

Cela garantit qu'aucun processus / threads ne peut accéder à la section critique en même temps.

Sandeep_black
la source