Qu'est ce qu'une condition?

lors de la rédaction d'applications multi-threads, l'un des problèmes les plus courants rencontrés sont les conditions de course.

mes questions à la communauté sont:

Qu'est-ce qu'une condition de race? Comment les détecter? Comment fais-tu? Enfin, comment les empêchez-vous de se produire?

762
demandé sur TylerH 2008-08-29 19:55:10

17 réponses

une condition de course se produit lorsque deux ou plusieurs threads peuvent accéder aux données partagées et qu'ils essaient de les modifier en même temps. Parce que l'algorithme d'ordonnancement des threads peut échanger entre les threads à tout moment, 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 du changement dans les données dépend de l'algorithme de programmation des threads, c'est-à-dire que les deux threads sont "en course" pour accéder aux données ou les modifier.

des problèmes se produisent souvent lorsque un thread fait un "check-then-act" (par exemple "check" si la valeur est X, puis "act" pour faire quelque chose qui dépend de la valeur étant X) et un autre thread fait quelque chose à la valeur entre le "check" et le "act". Par exemple:

if (x == 5) // The "Check"
{
   y = x * 2; // The "Act"

   // If another thread changed x in between "if (x == 5)" and "y = x * 2" above,
   // y will not be equal to 10.
}

le point étant, y pourrait être 10, ou il pourrait être n'importe quoi, selon si un autre fil changé x entre le contrôle et l'acte. Vous n'avez pas de véritable moyen de savoir.

afin d'empêcher les conditions de course de produit, que vous auriez normalement mettre un verrou autour de données partagées pour s'assurer qu'un seul thread peut accéder aux données à la fois. Cela signifierait quelque chose comme ceci:

// Obtain lock for x
if (x == 5)
{
   y = x * 2; // Now, nothing can change x until the lock is released. 
              // Therefore y = 10
}
// release lock for x
950
répondu Lehane 2015-04-07 11:03:02

Une "race condition" quand multithread (ou parallèle) le code d'accès à une ressource partagée pourrait le faire de manière à provoquer des résultats inattendus.

prendre cet exemple:

for ( int i = 0; i < 10000000; i++ )
{
   x = x + 1; 
}

si vous aviez 5 threads exécutant ce code à la fois, la valeur de x ne serait pas 50,000,000. Il serait, en effet, varier avec chaque exécution.

c'est parce que, pour chaque fil d'augmenter la la valeur de x, ils doivent faire ce qui suit: (simplifié, évidemment)

Retrieve the value of x
Add 1 to this value
Store this value to x

N'importe quel fil peut être à n'importe quelle étape dans ce processus à n'importe quel moment, et ils peuvent marcher sur l'autre quand une ressource partagée est impliquée. L'état de x peut être modifié par un autre thread pendant le temps entre x est lu et quand il est réécrit.

disons qu'un thread récupère la valeur de x, mais ne l'a pas encore stockée. Un autre thread peut également récupérer le même valeur de x (parce qu'aucun fil ne l'a encore changé) et alors ils stockeraient tous les deux la même valeur (x+1) dans x!

exemple:

Thread 1: reads x, value is 7
Thread 1: add 1 to x, value is now 8
Thread 2: reads x, value is 7
Thread 1: stores 8 in x
Thread 2: adds 1 to x, value is now 8
Thread 2: stores 8 in x

conditions de course peuvent être évitées en employant une sorte de mécanisme de verrouillage avant le code qui accède à la ressource partagée:

for ( int i = 0; i < 10000000; i++ )
{
   //lock x
   x = x + 1; 
   //unlock x
}

ici, la réponse apparaît comme 50.000.000 chaque temps.

pour en savoir plus sur le verrouillage, rechercher: mutex, sémaphore, section critique, ressource partagée.

180
répondu privatehuff 2015-11-12 19:31:01

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

vous prévoyez d'aller au cinéma à 17h. Vous vous renseignez sur la disponibilité des billets à 16h. Le représentant dit qu'ils sont disponibles. Vous vous détendez et vous arrivez à la billetterie 5 minutes avant le spectacle. Je suis sûr que vous pouvez deviner ce qui se passe: c'est une maison pleine. Le problème ici était dans la durée entre le contrôle et l'action. Vous vous êtes renseigné à 4 h et vous avez agi à 5 h. En attendant, quelqu'un d'autre attrapé les billets. Il s'agit d'une condition de race - en particulier un scénario de "check-then-act" des conditions de race.

Comment les détecter?

Religieux de la revue de code, multi-thread tests unitaires. Il n'y a pas de raccourci. Il y a peu de plugin Eclipse émergeant sur ce point, mais rien de stable pour l'instant.

Comment gérer et prévenir?

la meilleure chose serait de créer sans effets secondaires et apatrides fonctions, utiliser immutables autant que possible. Mais ce n'est pas toujours possible. Donc, à l'aide de java.util.simultané.des structures de données atomiques, simultanées, une synchronisation appropriée et une concurrence basée sur les acteurs seront utiles.

la meilleure ressource pour la concurrence est JCIP. Vous pouvez également obtenir plus de détails sur l'explication ci-dessus ici .

114
répondu Vishal Shukla 2015-08-05 06:11:31

il y a une différence technique importante entre les conditions de course et les courses de données. La plupart des réponses semblent supposer que ces termes sont équivalents, mais ce n'est pas le cas.

une course de données se produit lorsque 2 instructions accèdent au même emplacement de mémoire, au moins un de ces accès est une écriture et il n'y a pas de se produit avant de commander parmi ces accès. Maintenant, ce qui constitue un se produit avant de commander est sujet à beaucoup de débat, mais en général les paires ulock-lock sur la même variable de verrouillage et les paires wait-signal sur la même variable de condition induisent un happens-avant l'ordre.

une condition de course est une erreur sémantique. C'est un défaut qui se produit dans le timing ou l'ordre des événements qui conduit au programme erroné comportement .

de nombreuses conditions de course peuvent être (et sont en fait) causées par des courses de données, mais ce n'est pas nécessaire. Comme une question de fait, les données courses et les conditions de race ne sont ni nécessaires, ni suffisantes les unes pour les autres. Ce post de blog qui explique aussi la différence très bien, avec une simple opération bancaire par exemple. Voici un autre exemple simple qui explique la différence.

maintenant que nous avons précisé la terminologie, essayons de répondre à la question originale.

étant donné que les conditions de course sont des bogues sémantiques, il y a pas moyen de les détecter. C'est parce qu'il n'y a aucun moyen d'avoir un oracle automatisé qui puisse distinguer le comportement correct et incorrect du programme dans le cas général. La détection des races est un problème indécis.

d'autre part, les courses de données ont une définition précise qui ne se rapporte pas nécessairement à l'exactitude, et donc on peut les détecter. Il existe de nombreux types de détecteurs de course de données (Détection de course de données statique/dynamique, course de données basée sur lockset). détection, passe-avant que les données fondées sur la race de détection des hybrides, les données de la course de détection). Un détecteur de course de données dynamique de pointe est ThreadSanitizer qui fonctionne très bien dans la pratique.

Gérer les courses de données en général nécessite une certaine discipline de programmation pour induire des happens-avant les bords entre les accès aux données partagées (soit pendant le développement, ou une fois qu'ils sont détectés à l'aide des outils mentionnés ci-dessus). cela peut être fait par des serrures, condition variables, sémaphores,etc. Cependant, on peut aussi utiliser différents paradigmes de programmation comme le passage de messages (au lieu de la mémoire partagée) qui évitent les courses de données par construction.

53
répondu Baris Kasikci 2017-05-23 10:31:37

une sorte de définition canonique est " lorsque deux threads accèdent au même endroit dans la mémoire en même temps, et au moins un des accès est une écriture ."Dans la situation, le fil "reader" peut obtenir l'ancienne valeur ou la nouvelle valeur, selon le fil "gagne la course."Ce n'est pas toujours un bug-en fait, certains algorithmes de bas niveau vraiment chevelus le font exprès-mais cela devrait généralement être évité. @Steve Gury donner un bon exemple de quand il pourrait être un problème.

32
répondu Chris Conway 2008-08-29 16:21:41

une condition de race est une sorte de bug, qui se produit seulement avec certaines conditions temporelles.

exemple: Imaginez que vous avez deux fils, A et B.

Dans Le Fil A:

if( object.a != 0 )
    object.avg = total / object.a

Dans Le Fil B:

object.a = 0

si le thread A est préempté juste après avoir vérifié cet objet.a n'est pas nul, B fera a = 0 , et quand le thread a gagnera le processeur, il fera un "divide by zero".

ce bug ne se produit que lorsque le thread A est préempté juste après la déclaration if, il est très rare, mais il peut se produire.

29
répondu Steve Gury 2013-05-16 05:08:54

les conditions de course se produisent dans les applications multi-filetées ou les systèmes multi-processus. Une condition de race, à son plus fondamental, est tout ce qui fait l'hypothèse que deux choses qui ne sont pas dans le même fil ou le même processus se produiront dans un ordre particulier, sans prendre des mesures pour s'assurer qu'elles se produisent. Cela se produit généralement lorsque deux threads passent des messages en définissant et en vérifiant les variables membres d'une classe auxquelles tous deux peuvent accéder. Il y a presque toujours une condition de course quand un fil appelle le sommeil pour donner un autre temps de fil pour finir une tâche (à moins que ce sommeil est dans une boucle, avec un certain mécanisme de vérification).

les outils pour prévenir les conditions de course dépendent du langage et de L'OS, mais certains comones sont des Mutex, des sections critiques et des signaux. Les mutex sont bons quand on veut être sûr d'être le seul à faire quelque chose. Les signaux sont bons quand vous voulez vous assurer que quelqu'un d'autre a fini de faire quelque chose. Réduire au minimum les ressources partagées peut aussi aider à prévenir comportements inattendus

détecter les conditions de course peut être difficile, mais il ya quelques signes. Code qui dépend fortement sur les sleeps est sujette à des conditions de course, donc vérifiez d'abord les appels à dormir dans le code affecté. L'ajout de sleeps particulièrement longs peut également être utilisé pour le débogage pour essayer de forcer un ordre particulier d'événements. Cela peut être utile pour reproduire le comportement, voir si vous pouvez le faire disparaître en changeant le timing des choses, et pour tester les solutions mises en place. L'dort doit être retiré après le débogage.

le signe distinctif que l'on a une condition de race, cependant, est s'il y a un problème qui se produit seulement de façon intermittente sur certaines machines. Les insectes communs seraient les accidents et les blocages. Avec l'exploitation forestière, vous devriez être en mesure de trouver la zone touchée et de travailler à partir de là.

18
répondu tsellon 2008-08-29 16:12:09

condition de course n'est pas seulement liée au logiciel, mais aussi avec le matériel. En fait, le terme a d'abord été inventé par l'industrie du matériel.

selon wikipedia :

l'expression trouve son origine dans l'idée de deux signaux se chevauchant à influence la sortie d'abord .

condition de Race dans une logique circuit:

enter image description here

industrie du logiciel a pris ce terme sans modification, ce qui rend un peu difficile à comprendre.

Vous devez effectuer un remplacement de la carte pour le monde du logiciel:

  • "deux signaux" => "deux fils"/"deux processus"
  • " influence la sortie "= > " influence certains l'état partagé"

ainsi l'état de course dans l'industrie du Logiciel signifie"deux fils"/"deux processus" s'enchaînant pour "influencer un état partagé", et le résultat final de l'état partagé dépendra d'une certaine différence de temps subtile, qui pourrait être causée par un certain fil/ordre de lancement de processus spécifique, fil/ordonnancement de processus, etc.

11
répondu nybon 2018-09-25 22:54:27

Microsoft ont effectivement publié un article vraiment détaillé sur cette question des conditions de course et des blocages. Le résumé le plus résumé serait le paragraphe Titre:

une condition de course se produit lorsque deux threads accéder à une variable partagée à même temps. Le premier fil lit la variable, et le second thread lit la même valeur de la variable. Puis le premier fil et le deuxième fil exécute leurs opérations sur la valeur, et ils course pour voir quel thread peut écrire la valeur en dernier à la variable partagée. La valeur du fil qui écrit sa dernière valeur est préservée, parce que le fil est écrit sur la valeur que le précédent thread écrire.

7
répondu Konstantin Dinev 2012-09-14 08:00:50

une condition de race est une situation sur la programmation concurrente où deux fils ou processus concurrents et l'état final résultant dépend de qui obtient la ressource en premier.

4
répondu Jorge Córdoba 2008-08-29 16:07:57

Une condition de concurrence est une situation indésirable qui se produit lorsqu'un appareil ou d'un système tente d'effectuer deux ou plusieurs opérations en même temps, mais en raison de la nature du dispositif ou du système, les opérations doivent être effectuées dans le bon ordre pour être fait correctement.

dans la mémoire ou le stockage de l'ordinateur, une condition de course peut se produire si les commandes pour lire et écrire une grande quantité de données sont reçues presque au même instant, et la machine tente de Ecrivez une partie ou la totalité des anciennes données pendant que les anciennes sont encore en cours de lecture. Le résultat peut être un ou plusieurs des suivants: un crash d'ordinateur, une "opération illégale", une notification et l'arrêt du programme, des erreurs lisant les anciennes données, ou des erreurs écrivant les nouvelles données.

2
répondu dilbag koundal 2012-04-13 11:29:23

Voici l'exemple classique de Balance de compte bancaire qui aidera les débutants à comprendre facilement les Threads en Java W. R. T. conditions de course:

public class BankAccount {

/**
 * @param args
 */
int accountNumber;
double accountBalance;

public synchronized boolean Deposit(double amount){
    double newAccountBalance=0;
    if(amount<=0){
        return false;
    }
    else {
        newAccountBalance = accountBalance+amount;
        accountBalance=newAccountBalance;
        return true;
    }

}
public synchronized boolean Withdraw(double amount){
    double newAccountBalance=0;
    if(amount>accountBalance){
        return false;
    }
    else{
        newAccountBalance = accountBalance-amount;
        accountBalance=newAccountBalance;
        return true;
    }
}

public static void main(String[] args) {
    // TODO Auto-generated method stub
    BankAccount b = new BankAccount();
    b.accountBalance=2000;
    System.out.println(b.Withdraw(3000));

}
2
répondu realPK 2013-05-16 05:12:14

Ok c'est 4 questions. une réponse par une est comme ci-dessous....

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

il se produit lorsque la sortie et/ou le résultat du processus dépend de manière critique de la séquence ou du timing d'autres événements, c.-à-d. Par exemple 2 signaux s'activent pour changer la sortie en premier.

Comment les détecter?

il conduit à une erreur qui est difficile à localiser.

comment les gérez-vous?

Use Sémaphores

et enfin,

comment les empêchez-vous de se produire?

une façon d'éviter les conditions de course est d'utiliser un mécanisme de verrouillage pour les ressources. mais les ressources de verrouillage peuvent conduire à des blocages. qui doit être traitée.

2
répondu Adnan Qureshi 2014-11-14 14:46:11

essayez cet exemple de base pour mieux comprendre l'état de la race:

    public class ThreadRaceCondition {

    /**
     * @param args
     * @throws InterruptedException
     */
    public static void main(String[] args) throws InterruptedException {
        Account myAccount = new Account(22222222);

        // Expected deposit: 250
        for (int i = 0; i < 50; i++) {
            Transaction t = new Transaction(myAccount,
                    Transaction.TransactionType.DEPOSIT, 5.00);
            t.start();
        }

        // Expected withdrawal: 50
        for (int i = 0; i < 50; i++) {
            Transaction t = new Transaction(myAccount,
                    Transaction.TransactionType.WITHDRAW, 1.00);
            t.start();

        }

        // Temporary sleep to ensure all threads are completed. Don't use in
        // realworld :-)
        Thread.sleep(1000);
        // Expected account balance is 200
        System.out.println("Final Account Balance: "
                + myAccount.getAccountBalance());

    }

}

class Transaction extends Thread {

    public static enum TransactionType {
        DEPOSIT(1), WITHDRAW(2);

        private int value;

        private TransactionType(int value) {
            this.value = value;
        }

        public int getValue() {
            return value;
        }
    };

    private TransactionType transactionType;
    private Account account;
    private double amount;

    /*
     * If transactionType == 1, deposit else if transactionType == 2 withdraw
     */
    public Transaction(Account account, TransactionType transactionType,
            double amount) {
        this.transactionType = transactionType;
        this.account = account;
        this.amount = amount;
    }

    public void run() {
        switch (this.transactionType) {
        case DEPOSIT:
            deposit();
            printBalance();
            break;
        case WITHDRAW:
            withdraw();
            printBalance();
            break;
        default:
            System.out.println("NOT A VALID TRANSACTION");
        }
        ;
    }

    public void deposit() {
        this.account.deposit(this.amount);
    }

    public void withdraw() {
        this.account.withdraw(amount);
    }

    public void printBalance() {
        System.out.println(Thread.currentThread().getName()
                + " : TransactionType: " + this.transactionType + ", Amount: "
                + this.amount);
        System.out.println("Account Balance: "
                + this.account.getAccountBalance());
    }
}

class Account {
    private int accountNumber;
    private double accountBalance;

    public int getAccountNumber() {
        return accountNumber;
    }

    public double getAccountBalance() {
        return accountBalance;
    }

    public Account(int accountNumber) {
        this.accountNumber = accountNumber;
    }

    // If this method is not synchronized, you will see race condition on
    // Remove syncronized keyword to see race condition
    public synchronized boolean deposit(double amount) {
        if (amount < 0) {
            return false;
        } else {
            accountBalance = accountBalance + amount;
            return true;
        }
    }

    // If this method is not synchronized, you will see race condition on
    // Remove syncronized keyword to see race condition
    public synchronized boolean withdraw(double amount) {
        if (amount > accountBalance) {
            return false;
        } else {
            accountBalance = accountBalance - amount;
            return true;
        }
    }
}
0
répondu Morsu 2013-05-31 15:51:21

vous ne voulez pas toujours écarter une condition de course. Si vous avez un drapeau qui peut être lu et écrit par plusieurs threads, et ce drapeau est défini à 'done' par un thread de sorte que l'autre thread arrête le traitement lorsque le drapeau est défini à 'done', vous ne voulez pas que cette "condition de course" soit éliminée. En fait, celui-ci peut être considéré comme une condition de race bénigne.

Cependant, en utilisant un outil de détection de l'état de course, il sera repéré comme une condition de course nuisible.

plus de détails sur les conditions de course ici, http://msdn.microsoft.com/en-us/magazine/cc546569.aspx .

0
répondu octoback 2014-09-07 09:11:25

envisager une opération qui doit afficher le compte dès que le compte est incrémenté. IE., dès que CounterThread incréments la valeur DisplayThread doit afficher la valeur récemment mise à jour.

int i = 0;

sortie

CounterThread -> i = 1  
DisplayThread -> i = 1  
CounterThread -> i = 2  
CounterThread -> i = 3  
CounterThread -> i = 4  
DisplayThread -> i = 4

Ici CounterThread obtient le verrou et fréquemment mises à jour de la valeur avant DisplayThread l'affiche. Ici existe une condition de Race. Condition de course peut être résolu en utilisant la synchronisation

0
répondu bharanitharan 2015-07-15 08:06:48

Vous pouvez prévenir " race condition , si vous utilisez "Atomique" des classes. La raison est juste le fil ne pas séparer l'opération get et set, exemple est ci-dessous:

AtomicInteger ai = new AtomicInteger(2);
ai.getAndAdd(5);

en conséquence, vous aurez 7 dans le lien"ai". Bien que vous ayez fait deux actions, mais les deux opérations confirment le même thread et aucun autre thread n'interférera avec cela, cela signifie pas de conditions de course!

0
répondu Aleksei Moshkov 2017-08-19 18:19:46