multithreading - दौड़ की स्थिति क्या है?




concurrency terminology (12)

रेस कंडीशन क्या है?

आप 5 बजे एक फिल्म में जाने की योजना बना रहे हैं। आप 4 बजे टिकट की उपलब्धता के बारे में पूछताछ करते हैं। प्रतिनिधि कहते हैं कि वे उपलब्ध हैं। शो से 5 मिनट पहले आप आराम करें और टिकट विंडो तक पहुंचें। मुझे यकीन है कि आप अनुमान लगा सकते हैं कि क्या होता है: यह एक पूर्ण घर है। यहां समस्या जांच और कार्रवाई के बीच की अवधि में थी। आपने 4 पर पूछताछ की और 5 पर अभिनय किया। इस बीच, किसी और ने टिकट पकड़े। यह दौड़ की स्थिति है - विशेष रूप से दौड़ की स्थितियों के "चेक-फिर-एक्ट" परिदृश्य।

आप उन्हें कैसे पहचानते हैं?

धार्मिक कोड समीक्षा, बहु थ्रेडेड यूनिट परीक्षण। कोई शॉर्टकट नहीं है। इस पर उभर रहे कुछ ग्रहण प्लगइन हैं, लेकिन अभी तक कुछ भी स्थिर नहीं है।

आप उन्हें कैसे संभालें और रोकें?

सबसे अच्छी बात साइड-इफेक्ट फ्री और स्टेटलेस फ़ंक्शंस बनाने के लिए होगी, जितना संभव हो सके अपरिवर्तनीय का उपयोग करें। लेकिन यह हमेशा संभव नहीं है। तो java.util.concurrent.atomic, समवर्ती डेटा संरचनाओं, उचित सिंक्रनाइज़ेशन, और अभिनेता आधारित समरूपता का उपयोग करने में मदद मिलेगी।

समेकन के लिए सबसे अच्छा संसाधन जेसीआईपी है। आप यहां उपरोक्त स्पष्टीकरण पर कुछ और विवरण भी प्राप्त कर सकते हैं

बहु-थ्रेडेड अनुप्रयोगों को लिखते समय, अनुभव की जाने वाली सबसे आम समस्याओं में से एक दौड़ की स्थिति है।

समुदाय के लिए मेरे प्रश्न हैं:

दौड़ की स्थिति क्या है? आप उन्हें कैसे पहचानते हैं? आप उन्हें कैसे संभालेंगे? अंत में, आप उन्हें होने से कैसे रोकते हैं?


आप हमेशा दौड़ की स्थिति को त्यागना नहीं चाहते हैं। यदि आपके पास एक झंडा है जिसे कई धागे द्वारा पढ़ और लिखा जा सकता है, और यह ध्वज एक थ्रेड द्वारा 'किया गया' पर सेट किया गया है ताकि अन्य धागे प्रसंस्करण बंद हो जाएं जब ध्वज 'पूर्ण' पर सेट हो, तो आप नहीं चाहते कि "दौड़ हालत "समाप्त हो जाएगी। वास्तव में, इसे एक सौम्य दौड़ की स्थिति के रूप में जाना जा सकता है।

हालांकि, दौड़ की स्थिति का पता लगाने के लिए एक उपकरण का उपयोग करके, इसे हानिकारक दौड़ की स्थिति के रूप में देखा जाएगा।

रेस हालत पर अधिक जानकारी, http://msdn.microsoft.com/en-us/magazine/cc546569.aspx


एक ऑपरेशन पर विचार करें, जैसे ही गिनती बढ़ जाती है, उतनी ही गिनती प्रदर्शित करनी होगी। यानी, जैसे ही काउंटर थ्रेड मूल्य को बढ़ाता है डिस्प्ले थ्रेड को हाल ही में अपडेट किए गए मान को प्रदर्शित करने की आवश्यकता होती है।

int i = 0;

उत्पादन

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

यहां काउंटर थ्रेड को लॉक अक्सर प्राप्त होता है और डिस्प्ले थ्रेड इसे प्रदर्शित करने से पहले मान को अपडेट करता है। यहां रेस की स्थिति मौजूद है। सिंक्रनाइज़ेशन का उपयोग कर रेस कंडीशन को हल किया जा सकता है


एक दौड़ की स्थिति एक प्रकार की बग है, जो केवल कुछ अस्थायी स्थितियों के साथ होती है।

उदाहरण: कल्पना कीजिए कि आपके पास दो धागे हैं, ए और बी

थ्रेड ए में:

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

थ्रेड बी में:

object.a = 0

यदि थ्रेड ए को ऑब्जेक्ट की जांच करने के बाद ही छूट दी जाती है। ए शून्य नहीं है, बी a = 0 , और जब थ्रेड ए प्रोसेसर प्राप्त करेगा, तो यह "शून्य से विभाजित" होगा।

यह बग केवल तब होता है जब थ्रेड ए को केवल कथन के बाद छूट दी जाती है, यह बहुत दुर्लभ है, लेकिन ऐसा हो सकता है।


एक प्रकार की कैनोलिक परिभाषा है " जब दो धागे एक ही समय में स्मृति में एक ही स्थान तक पहुंचते हैं, और कम से कम एक पहुंच एक लेखन है ।" स्थिति में "पाठक" धागा पुराना मान या नया मान प्राप्त कर सकता है, जिस पर निर्भर करता है कि कौन सा धागा "दौड़ जीतता है।" यह हमेशा एक बग नहीं है-वास्तव में, कुछ वास्तव में बालों वाले निम्न-स्तरीय एल्गोरिदम उद्देश्य पर करते हैं-लेकिन इसे आम तौर पर टालना चाहिए। @ स्टेव ग्यूरी एक अच्छा उदाहरण है जब यह एक समस्या हो सकती है।


एक रेस हालत एक अवांछनीय स्थिति होती है जो तब होती है जब एक डिवाइस या सिस्टम एक ही समय में दो या दो से अधिक संचालन करने का प्रयास करता है, लेकिन डिवाइस या सिस्टम की प्रकृति के कारण, संचालन उचित अनुक्रम में किया जाना चाहिए ताकि क्रमबद्ध हो सके सही ढंग से किया

कंप्यूटर मेमोरी या स्टोरेज में, एक रेस स्थिति तब हो सकती है जब बड़ी मात्रा में डेटा पढ़ने और लिखने के लिए आदेश लगभग उसी पल में प्राप्त होते हैं, और मशीन कुछ पुराने या पुराने डेटा को ओवरराइट करने का प्रयास करती है, जबकि पुराना डेटा अभी भी हो रहा है पढ़ें। नतीजा निम्न में से एक या अधिक हो सकता है: एक कंप्यूटर क्रैश, एक "अवैध संचालन," अधिसूचना और प्रोग्राम का शटडाउन, पुराने डेटा को पढ़ने में त्रुटियां, या नए डेटा को लिखने में त्रुटियां।


दौड़ की स्थिति और डेटा दौड़ के बीच एक महत्वपूर्ण तकनीकी अंतर है। अधिकांश उत्तर इस धारणा को मानते हैं कि ये शर्तें बराबर हैं, लेकिन वे नहीं हैं।

एक डेटा रेस तब होती है जब 2 निर्देश समान स्मृति स्थान तक पहुंचते हैं, कम से कम इनमें से एक पहुंच एक लेखन है और इन पहुंचों के बीच आदेश देने से पहले कोई नहीं होता है । अब आदेश देने से पहले क्या होता है, बहुत बहस के अधीन होता है, लेकिन सामान्य लॉक वैरिएबल पर सामान्य उल-लॉक जोड़े और उसी स्थिति पर प्रतीक्षा-सिग्नल जोड़े एक होता है-पहले आदेश होता है।

एक दौड़ की स्थिति एक अर्थपूर्ण त्रुटि है। यह एक दोष है जो घटनाओं के समय या क्रम में होता है जो गलत कार्यक्रम व्यवहार की ओर जाता है।

डेटा रेस के कारण कई दौड़ की स्थिति (और वास्तव में हैं) हो सकती है, लेकिन यह आवश्यक नहीं है। वास्तव में, डेटा दौड़ और दौड़ की स्थिति न तो आवश्यक है, न ही एक दूसरे के लिए पर्याप्त स्थिति है। This ब्लॉग पोस्ट एक साधारण बैंक लेनदेन उदाहरण के साथ भी अंतर को बहुत अच्छी तरह से समझाता है। यहां एक और सरल example है जो अंतर बताता है।

अब जब हमने शब्दावली को कम किया है, तो हम मूल प्रश्न का उत्तर देने का प्रयास करें।

यह देखते हुए कि दौड़ की स्थिति अर्थपूर्ण बग हैं, उन्हें पहचानने का कोई सामान्य तरीका नहीं है। ऐसा इसलिए है क्योंकि स्वचालित ऑरैकल होने का कोई तरीका नहीं है जो सामान्य मामले में सही बनाम गलत प्रोग्राम व्यवहार को अलग कर सकता है। रेस का पता लगाना एक अपरिहार्य समस्या है।

दूसरी तरफ, डेटा दौड़ में एक सटीक परिभाषा होती है जो आवश्यक रूप से शुद्धता से संबंधित नहीं होती है, और इसलिए कोई उन्हें पहचान सकता है। डेटा रेस डिटेक्टरों के कई स्वाद हैं (स्थैतिक / गतिशील डेटा रेस डिटेक्शन, लॉकसेट-आधारित डेटा रेस डिटेक्शन, डेटा-आधारित डेटा रेस डिटेक्शन, हाइब्रिड डेटा रेस डिटेक्शन के पहले होता है)। कला गतिशील डेटा रेस डिटेक्टर की स्थिति ThreadSanitizer जो अभ्यास में बहुत अच्छी तरह से काम करती है।

सामान्य रूप से डेटा रेस को संभालने के लिए कुछ प्रोग्रामिंग अनुशासन की आवश्यकता होती है जो साझा डेटा तक पहुंच के बीच होता है (या तो विकास के दौरान, या उपरोक्त उल्लिखित टूल का उपयोग करके पता चला है)। यह ताले, हालत चर, सेमफोर इत्यादि के माध्यम से किया जा सकता है। हालांकि, कोई भी संदेश प्रोग्रामिंग (साझा स्मृति की बजाय) जैसे विभिन्न प्रोग्रामिंग प्रतिमानों को नियोजित कर सकता है जो निर्माण द्वारा डेटा दौड़ से बचते हैं।


दौड़ की स्थिति की बेहतर समझ के लिए इस मूल उदाहरण का प्रयास करें:

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

यदि आप "परमाणु" वर्गों का उपयोग करते हैं , तो आप दौड़ की स्थिति को रोक सकते हैं। कारण केवल थ्रेड ऑपरेशन को अलग और सेट नहीं करता है, उदाहरण नीचे है:

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

नतीजतन, आपके पास "एआई" लिंक 7 होगा। यद्यपि आपने दो क्रियाएं की हैं, लेकिन दोनों ऑपरेशन एक ही धागे की पुष्टि करते हैं और कोई अन्य धागा इस में हस्तक्षेप नहीं करेगा, इसका मतलब है कि कोई दौड़ की स्थिति नहीं है!


यहां शास्त्रीय बैंक खाता बैलेंस उदाहरण है जो जावा में थ्रेड को समझने के लिए नए लोगों की मदद करेगा आसानी से दौड़ की स्थिति:

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

}

रेस हालत न केवल सॉफ्टवेयर से संबंधित है बल्कि हार्डवेयर से भी संबंधित है। असल में शब्द हार्डवेयर उद्योग द्वारा शुरू किया गया था।

wikipedia मुताबिक:

यह शब्द दो संकेतों के विचार से उत्पन्न होता है जो पहले आउटपुट को प्रभावित करने के लिए एक-दूसरे को रेसिंग करते हैं

एक तर्क सर्किट में रेस की स्थिति:

सॉफ़्टवेयर उद्योग ने इस शब्द को संशोधन के बिना लिया, जो इसे समझने में थोड़ा मुश्किल बनाता है।

आपको इसे सॉफ्टवेयर दुनिया में मैप करने के लिए कुछ प्रतिस्थापन करने की आवश्यकता है:

  • "दो संकेत" => "दो धागे" / "दो प्रक्रियाएं"
  • "आउटपुट को प्रभावित करें" => "कुछ साझा राज्य को प्रभावित करें"

तो सॉफ़्टवेयर उद्योग में दौड़ की स्थिति का मतलब है "दो धागे" / "दो प्रक्रियाएं" एक दूसरे को "कुछ साझा राज्य को प्रभावित करने" के लिए रेसिंग करती हैं, और साझा राज्य का अंतिम परिणाम कुछ सूक्ष्म समय अंतर पर निर्भर करेगा, जो कुछ विशिष्ट कारणों से हो सकता है थ्रेड / प्रक्रिया लॉन्चिंग ऑर्डर, थ्रेड / प्रोसेस शेड्यूलिंग इत्यादि।


रेस हालत समवर्ती प्रोग्रामिंग की स्थिति है जहां दो समवर्ती धागे या प्रक्रियाएं होती हैं और परिणामी अंतिम स्थिति इस बात पर निर्भर करती है कि संसाधन को पहले कौन प्राप्त करता है।





race-condition