तो मैं इस अध्याय में एक पुस्तक के माध्यम से पढ़ रहा हूं जो मल्टीथ्रेडिंग और समवर्ती पर जाता है उन्होंने मुझे एक प्रश्न दिया जो वास्तव में मुझे समझ में नहीं आता है।

मुझे लगता है कि परम x के साथ 3 फ़ंक्शन बनाना है जो केवल x * x की गणना करता है; एक म्यूटेक्स का उपयोग कर रहा है, एक परमाणु प्रकार का उपयोग कर रहा है, और एक न तो उपयोग कर रहा है। और मान धारण करने वाले 3 वैश्विक चर बनाएं। पहले दो कार्य दौड़ की स्थिति को रोकेंगे लेकिन तीसरा नहीं हो सकता है।

उसके बाद मैं एन थ्रेड बनाता हूं और फिर लूप करता हूं और प्रत्येक थ्रेड को इसके एक्स फ़ंक्शन की गणना करने के लिए कहता हूं (3 अलग लूप, प्रत्येक फ़ंक्शन के लिए एक। इसलिए मैं 3 बार एन थ्रेड बना रहा हूं)

अब पुस्तक मुझे बताती है कि फ़ंक्शन 1 और 2 का उपयोग करके मुझे हमेशा सही उत्तर मिलना चाहिए लेकिन फ़ंक्शन 3 का उपयोग करके मुझे हमेशा सही उत्तर नहीं मिलेगा। हालांकि, मुझे हमेशा उन सभी का सही जवाब मिल रहा है। मुझे लगता है कि ऐसा इसलिए है क्योंकि मैं सिर्फ x * x की गणना कर रहा हूं जो कि यह सब करता है।

उदाहरण के तौर पर, जब एन = 3, सही मान 0 * 0 + 1 * 1 + 2 * 2 = 5 है।

यह परमाणु कार्य है:

void squareAtomic(atomic<int> x)
{
    accumAtomic += x * x;
}

और इस तरह मैं फ़ंक्शन को कॉल करता हूं

thread threadsAtomic[N]
for (int i = 0; i < N; i++) //i will be the current thread that represents x
    {
        threadsAtomic[i] = thread(squareAtomic, i);
    }

    for (int i = 0; i < N; i++)
    {
        threadsAtomic[i].join();
    }

यह वह कार्य है जिसे कभी-कभी दौड़ की स्थिति बनानी चाहिए:

void squareNormal(int x) 
{
    accumNormal += x * x;
}

यहां बताया गया है कि मैं इसे कैसे कॉल करता हूं:

thread threadsNormal[N];
    for (int i = 0; i < N; i++) //i will be the current thread that represents x
    {
        threadsNormal[i] = thread(squareNormal, i);
    }

    for (int i = 0; i < N; i++)
    {
        threadsNormal[i].join();
    }

यह सब मेरा अपना कोड है इसलिए हो सकता है कि मैं इस प्रश्न को सही ढंग से नहीं कर रहा हूं, और उस स्थिति में मैं क्षमा चाहता हूं।

0
John Baltimore 6 नवम्बर 2020, 07:44

1 उत्तर

सबसे बढ़िया उत्तर

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

इस मामले में आपके रेसी प्रोग्राम की रेस कंडीशन एक साथ कई थ्रेड पढ़ने और लिखने के रूप में आती है accumNormal; विशेष रूप से, आपको गलत परिणाम मिल सकता है यदि थ्रेड A accumNormal के मान को पढ़ता है, और फिर थ्रेड B accumNormal के लिए एक नया मान लिखता है, और फिर थ्रेड A एक नया लिखता है मान से accumNormal, थ्रेड B के मान को अधिलेखित कर दें।

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

2
Jeremy Friesner 6 नवम्बर 2020, 05:24