Wat is een raceconditie?

Bij het schrijven van toepassingen met meerdere threads is een van de meest voorkomende problemen de race-omstandigheden.

Mijn vragen aan de community zijn:

Wat is de raceconditie?
Hoe detecteer je ze?
Hoe ga je ermee om?
Tot slot, hoe voorkom je dat ze zich voordoen?


Antwoord 1, autoriteit 100%

Er treedt een raceconditie op wanneer twee of meer threads toegang hebben tot gedeelde gegevens en ze proberen deze tegelijkertijd te wijzigen. Omdat het thread scheduling-algoritme op elk moment tussen threads kan wisselen, weet u niet in welke volgorde de threads zullen proberen toegang te krijgen tot de gedeelde gegevens. Daarom is het resultaat van de wijziging in gegevens afhankelijk van het threadplanningsalgoritme, d.w.z. beide threads “racen” om toegang te krijgen tot de gegevens / deze te wijzigen.

Problemen treden vaak op wanneer een thread een “check-then-act” doet (bijv. “check” als de waarde X is, dan “act” om iets te doen dat afhankelijk is van de waarde X) en een andere thread iets doet om de waarde tussen de “check” en de “act”. Bijv.:

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.
}

Het punt is, y kan 10 zijn, of het kan van alles zijn, afhankelijk van of een andere thread x heeft veranderd tussen de check en act. Je kunt het niet echt weten.

Om te voorkomen dat er zich race-omstandigheden voordoen, plaatst u doorgaans een slot rond de gedeelde gegevens om ervoor te zorgen dat slechts één thread tegelijkertijd toegang heeft tot de gegevens. Dit zou zoiets als dit betekenen:

// 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

Antwoord 2, autoriteit 16%

Er is sprake van een “race-conditie” wanneer multithreaded (of anderszins parallelle) code die toegang zou krijgen tot een gedeelde bron, dit zou kunnen doen op een manier die onverwachte resultaten zou veroorzaken.

Neem dit voorbeeld:

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

Als je 5 threads tegelijk had die deze code uitvoerden, zou de waarde van x NIET 50.000.000 worden. Het zou in feite bij elke run variëren.

Dit komt omdat, om voor elke thread de waarde van x te verhogen, ze het volgende moeten doen: (vereenvoudigd, uiteraard)

Haal de waarde van x . op
Voeg 1 toe aan deze waarde
Sla deze waarde op in x

Elke thread kan op elk moment bij elke stap in dit proces zijn en ze kunnen op elkaar stappen als er een gedeelde bron bij betrokken is. De status van x kan worden gewijzigd door een andere thread gedurende de tijd tussen het lezen van x en het terugschrijven ervan.

Stel dat een thread de waarde van x ophaalt, maar deze nog niet heeft opgeslagen. Een andere thread kan ook de dezelfdewaarde van x ophalen (omdat er nog geen thread is gewijzigd) en dan zouden ze allebei de dezelfdewaarde (x+1) opslaan in x!

Voorbeeld:

Thread 1: leest x, waarde is 7
Onderwerp 1: tel 1 op bij x, waarde is nu 8
Discussie 2: leest x, waarde is 7
Discussie 1: slaat 8 op in x
Discussie 2: telt 1 op bij x, waarde is nu 8
Discussie 2: slaat 8 in x op

Race-omstandigheden kunnen worden vermeden door een soort vergrendeling-mechanisme toe te passen voor de code die toegang heeft tot de gedeelde bron:

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

Hier komt het antwoord elke keer uit op 50.000.000.

Zoek voor meer informatie over vergrendeling naar: mutex, semafoor, kritieke sectie, gedeelde bron.


Antwoord 3, autoriteit 11%

Wat is een raceconditie?

Je bent van plan om 17.00 uur naar de film te gaan. U informeert om 16.00 uur naar de beschikbaarheid van de tickets. De vertegenwoordiger zegt dat ze beschikbaar zijn. Je ontspant en bereikt het loket 5 minuten voor de show. Ik weet zeker dat je kunt raden wat er gebeurt: het is een full house. Het probleem hier zat in de duur tussen de controle en de actie. Je vroeg om 4 uur en handelde om 5. Ondertussen heeft iemand anders de kaartjes gepakt. Dat is een race-conditie – met name een “check-dan-act”-scenario van race-omstandigheden.

Hoe detecteer je ze?

Religieuze codebeoordeling, multi-threaded unit tests. Er is geen snelkoppeling. Er zijn maar weinig Eclipse-plug-ins op dit gebied, maar nog niets stabiel.

Hoe ga je ermee om en voorkom je ze?

Het beste zou zijn om neveneffectvrije en staatloze functies te creëren, en zoveel mogelijk onveranderlijke waarden te gebruiken. Maar dat is niet altijd mogelijk. Dus het gebruik van java.util.concurrent.atomic, gelijktijdige gegevensstructuren, juiste synchronisatie en op actoren gebaseerde gelijktijdigheid zal helpen.

De beste bron voor gelijktijdigheid is JCIP. Je kunt hier ook wat meer details over bovenstaande uitlegkrijgen.


Antwoord 4, autoriteit 5%

Er is een belangrijk technisch verschil tussen raceomstandigheden en dataraces. De meeste antwoorden lijken te veronderstellen dat deze termen equivalent zijn, maar dat is niet zo.

Er vindt een datarace plaats wanneer 2 instructies toegang krijgen tot dezelfde geheugenlocatie, ten minste één van deze toegangen een schrijfactie is en er geen gebeurt voor het bestellentussen deze toegangen. Wat nu een gebeurt vóór het bestellen is, is onderwerp van veel discussie, maar in het algemeen induceren ulock-lock-paren op dezelfde lock-variabele en wacht-signaalparen op dezelfde conditievariabele een happening-before-order.

Een raceconditie is een semantische fout. Het is een fout die optreedt in de timing of de volgorde van gebeurtenissen die leidt tot verkeerd programma gedrag.

Veel racecondities kunnen (en worden) veroorzaakt door dataraces, maar dit is niet noodzakelijk. Feitelijk zijn dataraces en racecondities noch de noodzakelijke, noch de voldoende voorwaarde voor elkaar. Dezeblogpost legt het verschil ook heel goed uit, met een eenvoudig voorbeeld van een banktransactie. Hier is nog een eenvoudige voorbeelddat het verschil verklaart.

Nu we de terminologie onder de knie hebben, kunnen we proberen de oorspronkelijke vraag te beantwoorden.

Aangezien racecondities semantische bugs zijn, is er geen algemene manier om ze te detecteren. Dit komt omdat er geen manier is om een geautomatiseerd orakel te hebben dat in het algemene geval correct versus onjuist programmagedrag kan onderscheiden. Rasdetectie is een onbeslisbaar probleem.

Aan de andere kant hebben dataraces een precieze definitie die niet noodzakelijkerwijs betrekking heeft op correctheid, en daarom kan men ze detecteren. Er zijn veel soorten datarace-detectoren (statische/dynamische datarace-detectie, lockset-gebaseerde datarace-detectie, happening-before-gebaseerde datarace-detectie, hybride datarace-detectie). Een ultramoderne dynamische datarace-detector is ThreadSanitizerdie werkt heel goed in de praktijk.

Het afhandelen van dataraces in het algemeen vereist enige programmeerdiscipline om happenings-vóór randen tussen toegangen tot gedeelde data te veroorzaken (ofwel tijdens de ontwikkeling, ofwel zodra ze zijn gedetecteerd met behulp van de bovengenoemde tools). dit kan worden gedaan door middel van sloten, conditievariabelen, semaforen, enz. Men kan echter ook verschillende programmeerparadigma’s gebruiken, zoals het doorgeven van berichten (in plaats van gedeeld geheugen) die dataraces door constructie vermijden.


Antwoord 5, autoriteit 3%

Een soort van canonieke definitie is “wanneer twee threads tegelijkertijd toegang krijgen tot dezelfde locatie in het geheugen, en ten minste één van de toegangen een schrijfbewerking is.” In de situatie kan de “reader”-thread de oude waarde of de nieuwe waarde krijgen, afhankelijk van welke thread “de race wint”. Dit is niet altijd een bug – sommige echt harige low-level algoritmen doen dit met opzet – maar het moet over het algemeen worden vermeden. @Steve Gury geeft een goed voorbeeld van wanneer het een probleem zou kunnen zijn.


Antwoord 6, autoriteit 2%

Een raceconditie is een soort bug, die alleen optreedt bij bepaalde tijdelijke condities.

Voorbeeld:
Stel je voor dat je twee threads hebt, A en B.

In draad A:

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

In draad B:

object.a = 0

Als thread A wordt gepreempt net nadat u hebt gecontroleerd of object.a niet null is, zal B a = 0doen, en wanneer thread A de processor krijgt, zal het een “delen door nul”.

Deze bug treedt alleen op als thread A wordt verwijderd net na de if-instructie, het is zeer zeldzaam, maar het kan gebeuren.


Antwoord 7, autoriteit 2%

Een race-conditie is een situatie bij gelijktijdig programmeren waarbij twee gelijktijdige threads of processen strijden om een resource en de resulterende uiteindelijke status afhangt van wie de resource als eerste krijgt.


Antwoord 8, autoriteit 2%

De raceconditie is niet alleen gerelateerd aan software, maar ook aan hardware. Eigenlijk is de term oorspronkelijk bedacht door de hardware-industrie.

Volgens wikipedia:

De term komt voort uit het idee van twee signalen die tegen elkaar racenom
eerst de output beïnvloeden.

Raceconditie in een logisch circuit:

De software-industrie heeft deze term ongewijzigd overgenomen, waardoor het een beetje moeilijk te begrijpen is.

Je moet iets vervangen om het toe te wijzen aan de softwarewereld:

  • “twee signalen” => “twee threads”/”twee processen”
  • “beïnvloed de uitvoer” => “beïnvloed een gedeelde staat”

Dus raceconditie in de software-industrie betekent “twee threads”/”twee processen” die elkaar racen om “een gedeelde status te beïnvloeden”, en het uiteindelijke resultaat van de gedeelde status zal afhangen van een subtiel timingverschil, dat kan worden veroorzaakt door een specifieke startvolgorde voor threads/processen, planning van threads/processen, enz.


Antwoord 9

Race-omstandigheden komen voor in toepassingen met meerdere threads of systemen met meerdere processen. Een race-conditie is in de basis alles wat de veronderstelling maakt dat twee dingen die niet in dezelfde thread of hetzelfde proces zitten, in een bepaalde volgorde zullen gebeuren, zonder stappen te ondernemen om ervoor te zorgen dat ze dat wel doen. Dit gebeurt meestal wanneer twee threads berichten doorgeven door lidvariabelen van een klasse in te stellen en te controleren waartoe beide groepen toegang hebben. Er is bijna altijd een raceconditie wanneer een thread sleep oproept om een andere thread de tijd te geven om een taak te voltooien (tenzij die slaap in een lus zit, met een of ander controlemechanisme).

Hulpmiddelen om race-omstandigheden te voorkomen zijn afhankelijk van de taal en het besturingssysteem, maar enkele veelvoorkomende zijn mutexen, kritieke secties en signalen. Mutexen zijn goed als je zeker wilt weten dat je de enige bent die iets doet. Signalen zijn goed als je zeker wilt weten dat iemand anders iets gedaan heeft. Het minimaliseren van gedeelde bronnen kan ook helpen onverwacht gedrag te voorkomen

Het detecteren van race-omstandigheden kan moeilijk zijn, maar er zijn een paar tekenen. Code die sterk afhankelijk is van slaap, is gevoelig voor race-omstandigheden, dus controleer eerst of er oproepen om te slapen in de betreffende code zijn. Het toevoegen van bijzonder lange slaapperioden kan ook worden gebruikt voor debuggen om te proberen een bepaalde volgorde van gebeurtenissen te forceren. Dit kan handig zijn om het gedrag te reproduceren, om te zien of je het kunt laten verdwijnen door de timing van dingen te veranderen, en voor het testen van ingezette oplossingen. De slaapplaatsen moeten na het debuggen worden verwijderd.

Het kenmerkende teken dat men echter een race-toestand heeft, is als er een probleem is dat alleen met tussenpozen op sommige machines gebeurt. Gewone bugs zouden crashen en impasses zijn. Met houtkap moet u het getroffen gebied kunnen vinden en vanaf daar werk.


Antwoord 10

Microsoft heeft daadwerkelijk een echt gedetailleerde artikel gepubliceerd over deze kwestie van race-omstandigheden en deadlocks. De meest samenvattende abstracte van het is de titel Paragraaf:

Er treedt een raceconditie op wanneer twee threads toegang hebben tot een gedeelde variabele op
dezelfde tijd. De eerste thread leest de variabele en de tweede
Discussie leest dezelfde waarde uit de variabele. Dan de eerste draad
en tweede thread voert hun activiteiten uit over de waarde en racen
Om te zien welke discode de waarde kan schrijven als laatste aan de gedeelde variabele.
De waarde van de draad die zijn laatste waarde schrijft, is bewaard gebleven,
omdat de draad over de waarde schrijft dat de vorige draad
schreef.


Antwoord 11

Wat is een raceconditie?

De situatie wanneer het proces kritisch afhankelijk is van de reeks of timing van andere gebeurtenissen.

Bijvoorbeeld,
Processor A en processor B Beide behoeften Identical Resource voor hun uitvoering.

Hoe detecteer je ze?

Er zijn hulpmiddelen om automatisch raceconditie te detecteren:

Hoe ga je ermee om?

Raceconditie kan worden afgehandeld door Mutexof Semaphores. Ze fungeren als een vergrendeling waarmee een proces een bron kan verwerven op basis van bepaalde vereisten om racecondities te voorkomen.

Hoe voorkom je dat ze zich voordoen?

Er zijn verschillende manieren om racecondities te voorkomen, zoals vermijding van kritieke secties.

  1. Geen twee processen tegelijkertijd in hun kritieke regio’s. (Wederzijdse uitsluiting)
  2. Er worden geen aannames gedaan over snelheden of het aantal CPU’s.
  3. Er wordt geen proces uitgevoerd buiten het kritieke gebied dat andere processen blokkeert.
  4. Geen enkel proces hoeft eeuwig te wachten om zijn kritieke gebied binnen te gaan. (A wacht op B-bronnen, B wacht op C-bronnen, C wacht op A-bronnen)

Antwoord 12

Een race-conditie is een ongewenste situatie die optreedt wanneer een apparaat of systeem twee of meer bewerkingen tegelijk probeert uit te voeren, maar vanwege de aard van het apparaat of systeem moeten de bewerkingen in de juiste volgorde worden uitgevoerd in om correct te worden uitgevoerd.

In het computergeheugen of de opslag kan een raceconditie optreden als opdrachten voor het lezen en schrijven van een grote hoeveelheid gegevens op bijna hetzelfde moment worden ontvangen en de machine probeert sommige of alle oude gegevens te overschrijven terwijl die oude gegevens wordt nog gelezen. Het resultaat kan een of meer van de volgende zijn: een computercrash, een “illegale handeling”, melding en afsluiten van het programma, fouten bij het lezen van de oude gegevens of fouten bij het schrijven van de nieuwe gegevens.


Antwoord 13

U kunt Race-toestand voorkomen , als u “Atomic” -klassen gebruikt. De reden is slechts de thread die geen bediening krijgt en ingesteld, bijvoorbeeld is hieronder:

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

Als gevolg hiervan heeft u 7 in Link “AI”.
Hoewel je twee acties hebt gedaan, bevestigen de beide operatie dezelfde draad en niemand interfereert hiermee, dat betekent geen racecondities!


Antwoord 14

Hier is het groepsaldo van de klassieke bankrekening die nieuwe bies zal helpen om threads in Java gemakkelijk te begrijpen W.R.T. Race-omstandigheden:

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));
}

Antwoord 15

Probeer dit basisvoorbeeld voor een beter begrip van raceconditie:

   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;
        }
    }
}

Antwoord 16

Je wilt een racevoorwaarde niet altijd weggooien. Als je een vlag hebt die door meerdere threads kan worden gelezen en geschreven, en deze vlag is door één thread op ‘gereed’ gezet, zodat de andere thread stopt met verwerken wanneer de vlag is ingesteld op ‘done’, dan wil je niet dat ‘race’ voorwaarde” te worden geëlimineerd. In feite kan dit een goedaardige race-aandoening worden genoemd.

Als je echter een tool gebruikt voor het detecteren van racecondities, wordt het gezien als een schadelijke raceconditie.

Meer details over racecondities vind je hier, http://msdn.microsoft.com /nl-nl/magazine/cc546569.aspx.


Antwoord 17

Overweeg een bewerking die de telling moet weergeven zodra de telling wordt verhoogd. dat wil zeggen, zodra CounterThreadde waarde verhoogt, moet DisplayThreadde recentelijk bijgewerkte waarde weergeven.

int i = 0;

Uitvoer

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

Hier haalt CounterThreadde vergrendeling regelmatig op en werkt de waarde bij voordat DisplayThreaddeze weergeeft. Hier bestaat een rasconditie. Raceconditie kan worden opgelost door synchronisatie te gebruiken


Antwoord 18

Een race-conditie is een ongewenste situatie die optreedt wanneer twee of meer processen tegelijkertijd toegang hebben tot de gedeelde gegevens en deze kunnen wijzigen. Dit gebeurde omdat er conflicterende toegangen tot een bron waren. Kritiek sectieprobleem kan raceconditie veroorzaken. Om de kritieke toestand in het proces op te lossen, hebben we slechts één proces tegelijk uitgeschakeld die de kritieke sectie uitvoert.

Other episodes