Qu'est-ce qu'une impasse?

159

Lors de l'écriture d'applications multithreads, l'un des problèmes les plus courants rencontrés est les blocages.

Mes questions à la communauté sont:

  1. Qu'est-ce qu'une impasse?

  2. Comment les détectez-vous?

  3. Les gérez-vous?

  4. Et enfin, comment les empêcher de se produire?

bmurphy1976
la source

Réponses:

207

Un verrou se produit lorsque plusieurs processus tentent d'accéder à la même ressource en même temps.

Un processus perd et doit attendre que l'autre se termine.

Un blocage se produit lorsque le processus en attente tient toujours une autre ressource dont le premier a besoin avant de pouvoir se terminer.

Donc, un exemple:

La ressource A et la ressource B sont utilisées par le processus X et le processus Y

  • X commence à utiliser A.
  • X et Y essaient de commencer à utiliser B
  • Y 'gagne' et obtient B en premier
  • maintenant Y doit utiliser A
  • A est verrouillé par X, qui attend Y

Le meilleur moyen d'éviter les blocages est d'éviter que les processus ne se croisent de cette manière. Réduisez au maximum le besoin de verrouiller quoi que ce soit.

Dans les bases de données, évitez d'apporter beaucoup de modifications à différentes tables en une seule transaction, évitez les déclencheurs et passez autant que possible à des lectures optimistes / sales / nolock.

Keith
la source
9
J'utilise le processus ici comme une généralisation, pas spécifiquement un processus OS. Il peut s'agir de threads, mais également d'applications ou de connexions de base de données complètement différentes. Le schéma est le même.
Keith
1
Salut, étant donné ce scénario: Thread A verrouille la ressource A et a un long processus. Thread B en attente de verrouillage de la ressource A. Utilisation du temps CPU: 20%, pouvez-vous considérer qu'il s'agit d'une situation de blocage?
rickyProgrammer
2
@rickyProgrammer non, c'est juste une attente de verrouillage régulière, bien que la différence soit un peu académique. B en attente lente A est un verrou, B en attente de A en attente de B est un blocage.
Keith
Le blocage est donc plus de deux processus avec des ressources verrouillées en attente de libération de ces ressources ..
rickyProgrammer
2
@rickyProgrammer c'est un verrou qui ne deviendra pas libre, peu importe combien de temps vous attendez, à cause de la file d'attente circulaire.
Keith
126

Permettez-moi d'expliquer un exemple réel (pas vraiment réel) pour une situation de blocage des films policiers. Imaginez qu'un criminel tient un otage et contre cela, un flic tient également un otage qui est un ami du criminel. Dans ce cas, le criminel ne va pas laisser partir l'otage si le flic ne laisse pas son ami se laisser aller. De plus, le flic ne laissera pas l'ami du criminel se laisser aller, à moins que le criminel ne libère l'otage. Il s'agit d'une situation indigne de confiance sans fin, car les deux parties insistent sur le premier pas l'une de l'autre.

Scène criminelle et policière

entrez la description de l'image ici

Donc, simplement, lorsque deux threads ont besoin de deux ressources différentes et que chacun d'eux a le verrou de la ressource dont l'autre a besoin, c'est une impasse.

Une autre explication de haut niveau de l'impasse: Broken Hearts

Vous sortez avec une fille et un jour après une dispute, les deux côtés sont navrés l'un à l'autre et attendent un appel je-suis-désolé-et-j'ai-manqué-vous . Dans cette situation, les deux parties veulent se communiquer si et seulement si l'une d'elles reçoit un appel Je-suis-désolé de l'autre. Parce que ni l'un ni l'autre ne va commencer la communication et attendre dans un état passif, les deux vont attendre que l'autre commence la communication qui se termine dans une situation de blocage.

Levent Divilioglu
la source
Les threads ne devraient-ils pas appartenir à des processus différents?, Les threads appartenant au même processus peuvent-ils également provoquer un blocage?
lordvcs
1
@diabolicfreak Peu importe si les threads appartiennent au même processus ou non.
Sam Malayek
2
Un autre exemple de la vie réelle pourrait être quatre voitures venant au croisement de deux routes égales dans quatre directions simultanément. Tout le monde doit céder la place à une voiture du côté droit, pour que personne ne puisse continuer.
LoBo
35

Les blocages ne se produiront que lorsque vous avez deux ou plusieurs verrous qui peuvent être acquis en même temps et qu'ils sont saisis dans un ordre différent.

Les moyens d'éviter les blocages sont:

  • éviter d'avoir des serrures (si possible),
  • éviter d'avoir plus d'une serrure
  • prenez toujours les serrures dans le même ordre.
Mats Fredriksson
la source
Le 3ème point pour éviter une impasse (toujours prendre les serrures dans le même ordre) est vital, ce qui est assez facile à oublier dans la pratique du codage.
Qiang Xu
20

Pour définir l'impasse, je définirais d'abord le processus.

Processus : Comme nous le savons, le processus n'est rien d'autre qu'un processus programen cours d'exécution.

Ressource : Pour exécuter un programme, un processus nécessite des ressources. Les catégories de ressources peuvent inclure la mémoire, les imprimantes, les processeurs, les fichiers ouverts, les lecteurs de bande, les CD-ROM, etc.

Blocage : le blocage est une situation ou une condition dans laquelle deux processus ou plus détiennent des ressources et tentent d'acquérir d'autres ressources, et ils ne peuvent pas libérer les ressources tant qu'ils n'ont pas terminé leur exécution.

Condition ou situation de blocage

entrez la description de l'image ici

Dans le diagramme ci-dessus, il y a deux processus P1 et p2 et il y a deux ressources R1 et R2 .

La ressource R1 est allouée au processus P1 et la ressource R2 est allouée au processus p2 . Pour terminer l'exécution du processus, P1 a besoin de la ressource R2 , donc P1 demande pour R2 , mais R2 est déjà alloué à P2 .

De la même manière, le processus P2 pour terminer son exécution a besoin de R1 , mais R1 est déjà alloué à P1 .

les deux processus ne peuvent pas libérer leur ressource tant qu'ils n'ont pas terminé leur exécution. Les deux attendent donc une autre ressource et ils attendront éternellement. Il s'agit donc d'une condition DEADLOCK .

Pour qu'une impasse se produise, quatre conditions doivent être remplies.

  1. Exclusion mutuelle - Chaque ressource est actuellement allouée à exactement un processus ou est disponible. (Deux processus ne peuvent pas contrôler simultanément la même ressource ou être dans leur section critique).
  2. Mettre en attente et attendre - les processus détenant actuellement des ressources peuvent demander de nouvelles ressources.
  3. Pas de préemption - Une fois qu'un processus détient une ressource, elle ne peut pas être retirée par un autre processus ou le noyau.
  4. Attente circulaire - Chaque processus attend d'obtenir une ressource qui est détenue par un autre processus.

et toutes ces conditions sont satisfaites dans le diagramme ci-dessus.

Varun
la source
8

Un blocage se produit lorsqu'un thread attend quelque chose qui ne se produit jamais.

En règle générale, cela se produit lorsqu'un thread attend un mutex ou un sémaphore qui n'a jamais été publié par le propriétaire précédent.

Cela se produit également fréquemment lorsque vous avez une situation impliquant deux threads et deux verrous comme celui-ci:

Thread 1               Thread 2

Lock1->Lock();         Lock2->Lock();
WaitForLock2();        WaitForLock1();   <-- Oops!

Vous les détectez généralement parce que les choses auxquelles vous vous attendez ne se produisent jamais ou que l'application se bloque complètement.

17 sur 26
la source
Un blocage se produit lorsqu'un thread attend quelque chose qui ne peut pas se produire.
Marquis of Lorne
4

Vous pouvez jeter un œil à ces merveilleux articles , dans la section Deadlock . C'est en C # mais l'idée est toujours la même pour les autres plateformes. Je cite ici pour une lecture facile

Un blocage se produit lorsque deux threads attendent chacun une ressource détenue par l'autre, de sorte qu'aucun ne peut continuer. La façon la plus simple d'illustrer cela est d'utiliser deux verrous:

object locker1 = new object();
object locker2 = new object();

new Thread (() => {
                    lock (locker1)
                    {
                      Thread.Sleep (1000);
                      lock (locker2);      // Deadlock
                    }
                  }).Start();
lock (locker2)
{
  Thread.Sleep (1000);
  lock (locker1);                          // Deadlock
}
onmyway133
la source
4

Le blocage est un problème courant dans les problèmes de multitraitement / multiprogrammation sous OS. Supposons qu'il y ait deux processus P1, P2 et deux ressources R1, R2 partageables globalement et dans la section critique les deux ressources doivent être accédées

Initialement, le système d'exploitation affecte R1 pour traiter P1 et R2 pour traiter P2. Comme les deux processus s'exécutent simultanément, ils peuvent commencer à exécuter leur code, mais le PROBLÈME survient lorsqu'un processus atteint la section critique. Donc le processus R1 attendra que le processus P2 libère R2 et vice versa ... Donc ils attendront pour toujours (CONDITION DE VERROUILLAGE).

Une petite ANALOGIE ...

Votre mère (OS),
vous (P1),
votre frère (P2),
Apple (R1),
couteau (R2),
section critique (couper la pomme avec un couteau).

Ta mère te donne la pomme et le couteau à ton frère au début.
Les deux sont heureux et jouent (exécutant leurs codes).
N'importe qui d'entre vous veut couper la pomme (section critique) à un moment donné.
Tu ne veux pas donner la pomme à ton frère.
Votre frère ne veut pas vous donner le couteau.
Vous allez donc tous les deux attendre très longtemps :)

Rohit Singh
la source
2

Un blocage se produit lorsque deux threads acquièrent des verrous qui empêchent l'un ou l'autre de progresser. La meilleure façon de les éviter est de les développer soigneusement. De nombreux systèmes embarqués se protègent contre eux en utilisant une minuterie de surveillance (une minuterie qui réinitialise le système chaque fois qu'il se bloque pendant un certain temps).

Joseph Sturtevant
la source
2

Un blocage se produit lorsqu'il existe une chaîne circulaire de threads ou de processus qui contiennent chacun une ressource verrouillée et essaient de verrouiller une ressource détenue par l'élément suivant de la chaîne. Par exemple, deux threads qui détiennent respectivement le verrou A et le verrou B et tentent tous deux d'acquérir l'autre verrou.

Marquis de Lorne
la source
Je vote pour toi. Votre réponse est plus concise que ci-dessus car ils provoquent un blocage de confusion par processus ou thread. Quelqu'un dit processus, quelqu'un dit fil :)
hainguyen
1

Un programme classique et très simple pour comprendre la situation de blocage : -

public class Lazy {

    private static boolean initialized = false;

    static {
        Thread t = new Thread(new Runnable() {
            public void run() {
                initialized = true;
            }
        });

        t.start();

        try {
            t.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    public static void main(String[] args) {
        System.out.println(initialized);
    }
}

Lorsque le thread principal appelle Lazy.main, il vérifie si la classe Lazy a été initialisée et commence à initialiser la classe. Le thread principal définit maintenant initialized sur false, crée et démarre un thread d'arrière-plan dont la méthode d'exécution définit initialized sur true et attend la fin du thread d'arrière-plan.

Cette fois, la classe est en cours d'initialisation par un autre thread. Dans ces circonstances, le thread actuel, qui est le thread d'arrière-plan, attend sur l'objet Class jusqu'à ce que l'initialisation soit terminée. Malheureusement, le thread qui effectue l'initialisation, le thread principal, attend que le thread d'arrière-plan se termine. Étant donné que les deux threads sont maintenant en attente l'un de l'autre, le programme est DEADLOCKED.

Vivek Pratap Singh
la source
0

Un blocage est un état d'un système dans lequel aucun processus / thread unique n'est capable d'exécuter une action. Comme mentionné par d'autres, un blocage est généralement le résultat d'une situation dans laquelle chaque processus / thread souhaite acquérir un verrou sur une ressource qui est déjà verrouillée par un autre (ou même le même) processus / thread.

Il existe différentes méthodes pour les trouver et les éviter. On réfléchit très fort et / ou on essaie beaucoup de choses. Cependant, gérer le parallélisme est notoirement difficile et la plupart des gens (sinon tous) ne pourront pas éviter complètement les problèmes.

Certaines méthodes plus formelles peuvent être utiles si vous êtes sérieux au sujet de ce type de problèmes. La méthode la plus pratique que je connaisse est d'utiliser l'approche de la théorie des processus. Ici, vous modélisez votre système dans un langage de processus (par exemple CCS, CSP, ACP, mCRL2, LOTOS) et utilisez les outils disponibles pour (modéliser) vérifier les blocages (et peut-être aussi d'autres propriétés). Les exemples d'outils à utiliser sont FDR, mCRL2, CADP et Uppaal. Certaines âmes courageuses pourraient même prouver que leurs systèmes sont sans impasse en utilisant des méthodes purement symboliques (démonstration du théorème; cherchez Owicki-Gries).

Cependant, ces méthodes formelles nécessitent généralement un certain effort (par exemple, apprendre les bases de la théorie des processus). Mais je suppose que c'est simplement une conséquence du fait que ces problèmes sont difficiles.

mweerden
la source
0

Un blocage est une situation qui se produit lorsque le nombre de ressources disponibles est inférieur à la demande du processus différent. Cela signifie que lorsque le nombre de ressources disponibles devient inférieur à ce qu'il est demandé par l'utilisateur, à ce moment-là, le processus passe en état d'attente.Certains temps d'attente augmente davantage et il n'y a aucune chance de vérifier le problème du manque de ressources alors cette situation est connue sous le nom de blocage. En fait, le blocage est un problème majeur pour nous et il ne se produit que dans le système d'exploitation multitâche .deadlock ne peut pas se produire dans un système d'exploitation à tâche unique car toutes les ressources sont présentes uniquement pour cette tâche en cours d'exécution ......

puja bharti
la source
0

Ci-dessus quelques explications sont sympas. J'espère que cela pourra également être utile: https://ora-data.blogspot.in/2017/04/deadlock-in-oracle.html

Dans une base de données, lorsqu'une session (par exemple ora) veut une ressource détenue par une autre session (par exemple des données), mais que cette session (données) veut également une ressource qui est détenue par la première session (ora). Il peut y avoir plus de 2 sessions impliquées également mais l'idée sera la même. En fait, les blocages empêchent certaines transactions de continuer à fonctionner. Par exemple: Supposons que ORA-DATA détient le verrou A et demande le verrou B Et SKU détient le verrou B et demande le verrou A.

Merci,

Sapna
la source
0

Un blocage se produit lorsqu'un thread attend la fin d'un autre thread et vice versa.

Comment éviter?
- Évitez les verrous imbriqués
- Évitez les verrous inutiles
- Utilisez la jointure de thread ()

Comment le détectez-vous?
exécutez cette commande dans cmd:

jcmd $PID Thread.print

référence : geeksforgeeks

Arun Raaj
la source
0

Les blocages ne se produisent pas uniquement avec les verrous, bien que ce soit la cause la plus fréquente. En C ++, vous pouvez créer un blocage avec deux threads et aucun verrou en demandant simplement à chaque thread d'appeler join () sur l'objet std :: thread pour l'autre.

Raghav Navada
la source
0

Contrôle d'accès concurrentiel basé sur le verrouillage

L'utilisation du verrouillage pour contrôler l'accès aux ressources partagées est sujette à des blocages, et le planificateur de transactions seul ne peut pas empêcher leur occurrence.

Par exemple, les systèmes de bases de données relationnelles utilisent divers verrous pour garantir les propriétés ACID des transactions .

Quel que soit le système de base de données relationnelle que vous utilisez, les verrous seront toujours acquis lors de la modification (par exemple, UPDATEou DELETE) d'un certain enregistrement de table. Sans verrouiller une ligne qui a été modifiée par une transaction en cours d'exécution, Atomicity serait compromis .

Qu'est-ce qu'une impasse

Comme je l'ai expliqué dans cet article , un blocage se produit lorsque deux transactions simultanées ne peuvent pas progresser car chacune attend que l'autre libère un verrou, comme illustré dans le diagramme suivant.

entrez la description de l'image ici

Étant donné que les deux transactions sont en phase d'acquisition de verrouillage, aucune des deux ne libère de verrou avant d'acquérir la suivante.

Se remettre d'une situation de blocage

Si vous utilisez un algorithme de contrôle d'accès concurrentiel qui repose sur des verrous, il existe toujours un risque de s'exécuter dans une situation de blocage. Des blocages peuvent se produire dans n'importe quel environnement de concurrence, pas seulement dans un système de base de données.

Par exemple, un programme multithreading peut se bloquer si deux ou plusieurs threads attendent des verrous qui ont été précédemment acquis afin qu'aucun thread ne puisse progresser. Si cela se produit dans une application Java, la JVM ne peut pas simplement forcer un Thread à arrêter son exécution et à libérer ses verrous.

Même si la Threadclasse expose une stopméthode, cette méthode est obsolète depuis Java 1.1 car elle peut laisser les objets dans un état incohérent après l'arrêt d'un thread. Au lieu de cela, Java définit une interruptméthode, qui agit comme un indice car un thread qui est interrompu peut simplement ignorer l'interruption et continuer son exécution.

Pour cette raison, une application Java ne peut pas se remettre d'une situation de blocage, et il est de la responsabilité du développeur de l'application d'ordonner les demandes d'acquisition de verrou de manière à ce que les blocages ne puissent jamais se produire.

Cependant, un système de base de données ne peut pas appliquer un ordre d'acquisition de verrou donné car il est impossible de prévoir quels autres verrous une transaction donnée voudra acquérir davantage. La préservation de l'ordre de verrouillage devient la responsabilité de la couche d'accès aux données, et la base de données ne peut que faciliter la récupération après une situation de blocage.

Le moteur de base de données exécute un processus distinct qui analyse le graphique de conflit actuel pour les cycles d'attente de verrouillage (qui sont causés par des blocages). Lorsqu'un cycle est détecté, le moteur de base de données sélectionne une transaction et l'abandonne, provoquant la libération de ses verrous, afin que l'autre transaction puisse progresser.

Contrairement à la JVM, une transaction de base de données est conçue comme une unité de travail atomique. Par conséquent, une restauration laisse la base de données dans un état cohérent.

Pour plus de détails sur ce sujet, consultez également cet article .

Vlad Mihalcea
la source
-2

Mutex est essentiellement un verrou, fournissant un accès protégé aux ressources partagées. Sous Linux, le type de données du mutex de thread est pthread_mutex_t. Avant utilisation, initialisez-le.

Pour accéder aux ressources partagées, vous devez verrouiller le mutex. Si le mutex est déjà sur le verrou, l'appel bloquera le thread jusqu'à ce que le mutex soit déverrouillé. À la fin de la visite des ressources partagées, vous devez les déverrouiller.

Dans l'ensemble, il existe quelques principes de base non écrits:

  • Obtenez le verrou avant d'utiliser les ressources partagées.

  • Maintenir la serrure le moins longtemps possible.

  • Relâchez le verrou si le thread renvoie une erreur.

Marcus Thornton
la source
3
Cela décrit un verrou, pas une impasse.
Marquis de Lorne