Qt 5.11 - Reentrancy and Thread-Safety

रीएनट्रैनसी और थ्रेड-सेफ्टी




qt

रीएनट्रैनसी और थ्रेड-सेफ्टी

प्रलेखन के दौरान, वर्गों और कार्यों को चिह्नित करने के लिए शब्द रेफरेंट और थ्रेड-सेफ का उपयोग यह दर्शाने के लिए किया जाता है कि उनका उपयोग बहुसंख्या में कैसे किया जा सकता है:

  • एक थ्रेड-सुरक्षित फ़ंक्शन को कई थ्रेड्स से एक साथ बुलाया जा सकता है, तब भी जब इनवोकेशन साझा डेटा का उपयोग करते हैं, क्योंकि साझा किए गए डेटा के सभी संदर्भ क्रमबद्ध होते हैं।
  • एक रिपेंटेंट फ़ंक्शन को कई थ्रेड्स से एक साथ भी कहा जा सकता है, लेकिन केवल अगर प्रत्येक इनवोकेशन अपने डेटा का उपयोग करता है।

इसलिए, एक थ्रेड-सेफ फंक्शन हमेशा रीवेंटेंट होता है , लेकिन एक रेंटेंट फंक्शन हमेशा थ्रेड-सेफ नहीं होता है।

विस्तार से, एक वर्ग को पुनर्वित्त कहा जाता है यदि इसके सदस्य कार्यों को कई थ्रेड्स से सुरक्षित रूप से कहा जा सकता है, जब तक कि प्रत्येक थ्रेड क्लास के एक अलग उदाहरण का उपयोग करता है। कक्षा थ्रेड-सुरक्षित है यदि इसके सदस्य फ़ंक्शन को कई थ्रेड्स से सुरक्षित रूप से कॉल किया जा सकता है, भले ही सभी थ्रेड्स क्लास के एक ही उदाहरण का उपयोग करें।

नोट: क्यूटी वर्गों को केवल थ्रेड-सुरक्षित के रूप में प्रलेखित किया जाता है, यदि उनका उपयोग कई थ्रेड द्वारा किया जाना है। यदि किसी फ़ंक्शन को थ्रेड-सेफ या रीएन्ट्रेंट के रूप में चिह्नित नहीं किया गया है, तो इसका उपयोग विभिन्न थ्रेड्स से नहीं किया जाना चाहिए। यदि किसी वर्ग को थ्रेड-सेफ या रीटरेंट के रूप में चिह्नित नहीं किया जाता है, तो उस वर्ग के एक विशिष्ट उदाहरण को विभिन्न थ्रेड्स से एक्सेस नहीं किया जाना चाहिए।

reentrancy

C ++ क्लासेस अक्सर रीवेंटेंट होते हैं, बस इसलिए कि वे केवल अपने स्वयं के सदस्य डेटा तक पहुंचते हैं। कोई भी धागा एक सदस्य फ़ंक्शन को एक रेन्टेंट वर्ग की आवृत्ति पर कॉल कर सकता है, जब तक कि कोई अन्य धागा क्लास के एक ही समय में एक सदस्य फ़ंक्शन को कॉल नहीं कर सकता। उदाहरण के लिए, नीचे दिए गए Counter वर्ग में शामिल है:

class Counter
{
public:
    Counter() { n = 0; }

    void increment() { ++n; }
    void decrement() { --n; }
    int value() const { return n; }

private:
    int n;
};

वर्ग थ्रेड-सुरक्षित नहीं है, क्योंकि यदि कई थ्रेड्स डेटा सदस्य n को संशोधित करने का प्रयास करते हैं, तो परिणाम अपरिभाषित है। ऐसा इसलिए है क्योंकि ++ और -- ऑपरेटर हमेशा परमाणु नहीं होते हैं। वास्तव में, वे आमतौर पर तीन मशीन निर्देशों का विस्तार करते हैं:

  1. चर का मान एक रजिस्टर में लोड करें।
  2. रजिस्टर के मूल्य में वृद्धि या वृद्धि।
  3. मुख्य मेमोरी में वापस रजिस्टर के मूल्य को स्टोर करें।

यदि थ्रेड ए और थ्रेड बी चर के पुराने मान को एक साथ लोड करते हैं, तो उनके रजिस्टर में वृद्धि करें, और इसे वापस स्टोर करें, वे एक-दूसरे को ओवरराइट कर रहे हैं, और चर केवल एक बार बढ़ा हुआ है!

थ्रेड-सुरक्षा

स्पष्ट रूप से, पहुंच को क्रमबद्ध किया जाना चाहिए: थ्रेड ए को स्टेप्स (1), 3, बिना किसी रुकावट के (एटोमिकली) स्टेप बी के पहले ही स्टेप्स करने चाहिए; या ठीक इसके विपरीत। क्लास थ्रेड को सुरक्षित बनाने का एक आसान तरीका है कि QMutex साथ डेटा सदस्यों तक सभी पहुंच की रक्षा करना:

class Counter
{
public:
    Counter() { n = 0; }

    void increment() { QMutexLocker locker(&mutex); ++n; }
    void decrement() { QMutexLocker locker(&mutex); --n; }
    int value() const { QMutexLocker locker(&mutex); return n; }

private:
    mutable QMutex mutex;
    int n;
};

QMutexLocker वर्ग स्वचालित रूप से अपने कंस्ट्रक्टर में म्यूटेक्स को लॉक कर देता है और फ़ंक्शन के अंत में विध्वंसक का आह्वान करने पर इसे अनलॉक कर देता है। म्यूटेक्स को लॉक करना सुनिश्चित करता है कि विभिन्न थ्रेड्स से पहुंच को क्रमबद्ध किया जाएगा। mutex डेटा सदस्य को mutable क्वालीफायर के साथ घोषित किया जाता है क्योंकि हमें म्यूटेक्स को value() में लॉक और अनलॉक करने की आवश्यकता होती है, जो एक कॉन्स्टेबल फंक्शन है।

क्यूटी कक्षाओं पर नोट्स

कई क्यूटी क्लासेस रीइंन्ट्रेंट होते हैं, लेकिन उन्हें थ्रेड-सेफ नहीं बनाया जाता है, क्योंकि उन्हें थ्रेड-सेफ बनाने से बार-बार लॉक करने और QMutex अनलॉक करने के अतिरिक्त ओवरहेड हो QMutex । उदाहरण के लिए, QString है, लेकिन थ्रेड-सुरक्षित नहीं है। आप एक साथ कई थ्रेड्स से QString विभिन्न इंस्टेंस को सुरक्षित रूप से एक्सेस कर सकते हैं, लेकिन आप एक साथ कई थ्रेड्स से QMutex के समान इंस्टेंस को एक साथ एक्सेस नहीं कर सकते (जब तक कि आप खुद को QMutex से एक्सेस की सुरक्षा नहीं करते)।

कुछ क्यूटी कक्षाएं और फ़ंक्शन थ्रेड-सुरक्षित हैं। ये मुख्य रूप से थ्रेड से संबंधित कक्षाएं (जैसे QMutex ) और मूलभूत कार्य (जैसे QCoreApplication::postEvent ()) हैं।

नोट: मल्टीथ्रेडिंग डोमेन में शब्दावली पूरी तरह से मानकीकृत नहीं है। POSIX, रीवेंट्रेंट और थ्रेड-सेफ़ की परिभाषाओं का उपयोग करता है जो इसके C API के लिए कुछ अलग हैं। Qt के साथ अन्य ऑब्जेक्ट-ओरिएंटेड C ++ क्लास लाइब्रेरीज़ का उपयोग करते समय, सुनिश्चित करें कि परिभाषाएँ समझ में आती हैं।