Qt 5.11 - Synchronizing Threads

सूत्र सिंक्रनाइज़ करना




qt

सूत्र सिंक्रनाइज़ करना

जबकि थ्रेड्स का उद्देश्य कोड को समानांतर में चलने देना है, ऐसे समय होते हैं, जहां थ्रेड्स रुकने चाहिए और अन्य थ्रेड्स का इंतजार करना चाहिए। उदाहरण के लिए, यदि दो सूत्र एक ही चर में एक साथ लिखने का प्रयास करते हैं, तो परिणाम अपरिभाषित है। धागे को एक दूसरे की प्रतीक्षा करने के लिए मजबूर करने के सिद्धांत को पारस्परिक बहिष्कार कहा जाता है। यह साझा संसाधनों जैसे डेटा की सुरक्षा के लिए एक सामान्य तकनीक है।

क्यूटी थ्रेड्स को सिंक्रनाइज़ करने के लिए निम्न-स्तरीय प्राइमिटिव्स के साथ-साथ उच्च-स्तरीय तंत्र प्रदान करता है।

निम्न-स्तरीय सिंक्रनाइज़ेशन प्रिमिटिव

QMutex आपसी बहिष्कार को लागू करने के लिए बुनियादी वर्ग है। साझा संसाधन तक पहुँच प्राप्त करने के लिए एक थ्रेड म्यूटेक्स को लॉक करता है। यदि दूसरा धागा म्यूटेक्स को लॉक करने की कोशिश करता है जबकि यह पहले से ही लॉक है, तो दूसरा धागा तब तक सोने के लिए रखा जाएगा जब तक कि पहला धागा अपना कार्य पूरा नहीं कर लेता है और म्यूटेक्स को अनलॉक कर देता है।

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

QSemaphore का एक सामान्यीकरण है जो एक निश्चित संख्या में समान संसाधनों की सुरक्षा करता है। इसके विपरीत, एक QMutex ठीक एक संसाधन की रक्षा करता है। सेमाफोरस उदाहरण सेमाफोरस के एक विशिष्ट अनुप्रयोग को दर्शाता है: एक निर्माता और एक उपभोक्ता के बीच एक परिपत्र बफर तक पहुंच को सिंक्रनाइज़ करना।

QWaitCondition थ्रेड्स को सिंक्रनाइज़ करता है न कि आपसी अपवर्जन को लागू करने के द्वारा बल्कि एक स्थिति चर प्रदान करके। जबकि अन्य प्राइमेटिव थ्रेड को प्रतीक्षा करते हैं जब तक कि कोई संसाधन अनलॉक नहीं किया जाता है, QWaitCondition थ्रेड को तब तक प्रतीक्षा करता है जब तक कि किसी विशेष शर्त को पूरा नहीं किया गया हो। वेटिंग थ्रेड्स को आगे बढ़ने के लिए, wakeOne() को बेतरतीब ढंग से चुने हुए थ्रेड या wakeAll() को एक साथ जागृत करने के लिए कॉल करें। प्रतीक्षा की स्थिति का उदाहरण दिखाता है कि QWaitCondition बजाय QWaitCondition का उपयोग करके निर्माता-उपभोक्ता समस्या को कैसे हल किया QSemaphore

नोट: Qt की सिंक्रोनाइज़ेशन कक्षाएं ठीक से संरेखित बिंदुओं के उपयोग पर निर्भर करती हैं। उदाहरण के लिए, आप MSVC के साथ पैक्ड क्लासेस का उपयोग नहीं कर सकते।

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

जोखिम

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

एक अन्य समान परिदृश्य एक गतिरोध है । उदाहरण के लिए, मान लें कि थ्रेड A एक संसाधन को अनलॉक करने के लिए थ्रेड B की प्रतीक्षा कर रहा है। यदि थ्रेड बी भी एक अलग संसाधन को अनलॉक करने के लिए थ्रेड ए की प्रतीक्षा कर रहा है, तो दोनों थ्रेड हमेशा के लिए समाप्त हो जाएंगे, इसलिए एप्लिकेशन फ्रीज हो जाएगा।

सुविधा वर्ग

QMutexLocker , QReadLocker और QWriteLocker सुविधा वर्ग हैं जो QMutex और QReadWriteLock का उपयोग करना आसान QReadWriteLock । जब वे निर्मित होते हैं, तो वे एक संसाधन को लॉक कर देते हैं, और नष्ट होने पर स्वचालित रूप से इसे अनलॉक कर देते हैं। वे कोड को सरल बनाने के लिए डिज़ाइन किए गए हैं जो QMutex और QReadWriteLock उपयोग करते हैं, इस प्रकार उन अवसरों को कम करते हैं कि एक संसाधन दुर्घटना से स्थायी रूप से बंद हो जाता है।

उच्च-स्तरीय ईवेंट कतार

इंटर-थ्रेड संचार के लिए क्यूटी की घटना प्रणाली बहुत उपयोगी है। प्रत्येक थ्रेड का अपना ईवेंट लूप हो सकता है। किसी अन्य थ्रेड में एक स्लॉट (या किसी भी invokable विधि) को कॉल करने के लिए, लक्ष्य थ्रेड के इवेंट लूप में कॉल करें। यह स्लॉट चालू होने से पहले लक्ष्य थ्रेड को अपना वर्तमान कार्य पूरा करने देता है, जबकि मूल धागा समानांतर में चलता रहता है।

ईवेंट लूप में एक आमंत्रण रखने के लिए, एक कतारबद्ध signal-slot कनेक्शन बनाएं। जब भी सिग्नल उत्सर्जित होता है, तो उसके तर्कों को इवेंट सिस्टम द्वारा रिकॉर्ड किया जाएगा। सिग्नल रिसीवर जिस थ्रेड में रहता है, वह स्लॉट चलाएगा। वैकल्पिक रूप से, संकेतों के बिना समान प्रभाव प्राप्त करने के लिए QMetaObject::invokeMethod () को कॉल करें। दोनों मामलों में, एक कतारबद्ध कनेक्शन का उपयोग किया जाना चाहिए क्योंकि एक सीधा कनेक्शन घटना प्रणाली को बायपास करता है और वर्तमान थ्रेड में तुरंत विधि चलाता है।

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

कहा गया है कि, Qt की घटना प्रणाली, अंतर्निहित साझा डेटा संरचनाओं के साथ, पारंपरिक थ्रेड लॉकिंग का एक विकल्प प्रदान करती है। यदि सिग्नल और स्लॉट का उपयोग विशेष रूप से किया जाता है और थ्रेड्स के बीच कोई चर साझा नहीं किया जाता है, तो एक मल्टीथ्रेडेड प्रोग्राम पूरी तरह से निम्न-स्तर की प्राइमेटिविटी के बिना कर सकता है।

यह भी देखें QThread::exec () और थ्रेड्स और QObjects