पढ़ी बाधाएं और बाधाएं लिखना; बाधाओं को प्राप्त करें और बाधाओं को छोड़ दें। और अधिक (io बनाम स्मृति, आदि)।
बाधाएं मूल्यों के "नवीनतम" मूल्य या "ताजगी" को नियंत्रित करने के लिए नहीं हैं। वे मेमोरी एक्सेस के रिश्तेदार क्रम को नियंत्रित करने के लिए वहां हैं।
बाधाओं को लिखने के क्रम को नियंत्रित करें लिखें। चूंकि स्मृति में लिखना धीमा होता है (सीपीयू की गति की तुलना में), आम तौर पर एक लेखन-अनुरोध कतार होती है जहां लिखने से पहले पोस्ट किया जाता है। यद्यपि वे क्रम में कतारबद्ध हैं, जबकि कतार के अंदर लिखने को फिर से व्यवस्थित किया जा सकता है। (तो हो सकता है कि 'कतार' सबसे अच्छा नाम न हो ...) जब तक आप रीडरिंग को रोकने के लिए लिखने की बाधाओं का उपयोग न करें।
पढ़ें बाधाओं को पढ़ने के क्रम को नियंत्रित करें। सट्टा निष्पादन की वजह से (सीपीयू आगे दिखता है और स्मृति से लोड होता है) और लिखने वाले बफर के अस्तित्व के कारण (सीपीयू मेमोरी के बजाय लिखने वाले बफर से एक मान पढ़ेगा यदि यह वहां है - यानी सीपीयू सोचता है कि यह सिर्फ एक्स लिखा है = 5, फिर इसे वापस क्यों पढ़ें, बस यह देखें कि यह अभी भी 5 लिखने वाले बफर में प्रतीक्षा कर रहा है) पढ़ता क्रम से बाहर हो सकता है।
यह संकुलक है कि संकलक जेनरेट कोड के आदेश के संबंध में क्या करने का प्रयास करता है। यानी सी ++ में 'अस्थिर' यहां मदद नहीं करेगा, क्योंकि यह केवल "मेमोरी" से मूल्य को फिर से पढ़ने के लिए आउटपुट कोड को संकलक को बताता है, यह सीपीयू को यह नहीं बताता है कि इसे कैसे/कहां से पढ़ा जाए (यानी "स्मृति" सीपीयू स्तर पर कई चीजें हैं)।
तो पढ़ना/लिखना बाधाएं पढ़ने/लिखने वाली कतारों में पुनरावृत्ति को रोकने के लिए ब्लॉक डालती हैं (पठन आमतौर पर कतार का इतना अधिक नहीं होता है, लेकिन पुनरावृत्ति प्रभाव समान होते हैं)।
किस प्रकार के ब्लॉक? - ब्लॉक प्राप्त करें और/या रिलीज करें।
मोल - जैसे-पढ़ने के लिए अधिग्रहण (एक्स) पढ़ने कतार में एक्स के पढ़ने जोड़ सकते हैं और कतार (वास्तव में कतार फ्लश नहीं फ्लश, लेकिन यह कहते हुए इस पढ़ने से पहले कुछ भी पुन: व्यवस्थित नहीं है एक मार्कर जोड़ देगा , जैसे कि कतार फ्लश किया गया था)। तो बाद में (कोड ऑर्डर में) पढ़ा जा सकता है, लेकिन एक्स के पढ़ने से पहले नहीं।
रिलीज - उदाहरण के लिए लिखना-रिलीज (एक्स, 5) पहले कतार फ्लश करेगा (या मार्कर), फिर लेखन-कतार में लेखन-अनुरोध जोड़ें। तो पहले लिखते हैं x = 5 के बाद होने के लिए पुन: व्यवस्थित नहीं होंगे, लेकिन ध्यान दें कि बाद में लिखने को x = 5.
ध्यान दें कि मैंने रिलीज के साथ पढ़ने और लिखने के साथ पढ़ा है क्योंकि यह सामान्य है, लेकिन विभिन्न संयोजन संभव हैं।
प्राप्त करें और रिलीज को 'आधे बाधाओं' या 'आधे बाड़' माना जाता है क्योंकि वे केवल एक ही रास्ता जाने से पीछे हटना बंद कर देते हैं।
एक पूर्ण बाधा (या पूर्ण बाड़) एक अधिग्रहण और एक रिलीज दोनों लागू होता है - यानी कोई पुनरावृत्ति नहीं।
आमतौर पर लॉकफ्री प्रोग्रामिंग, या सी # या जावा 'अस्थिर' के लिए, जो आप चाहते हैं/चाहिए पढ़ना और लिखना-रिलीज करना है।
यानी
void threadA()
{
foo->x = 10;
foo->y = 11;
foo->z = 12;
write_release(foo->ready, true);
bar = 13;
}
void threadB()
{
w = some_global;
ready = read_acquire(foo->ready);
if (ready)
{
q = w * foo->x * foo->y * foo->z;
}
else
calculate_pi();
}
तो, सब से पहले, यह एक बुरा तरीका धागे कार्यक्रम है। ताले सुरक्षित होंगे। लेकिन बस बाधाओं को चित्रित करने के लिए ...
थ्रेडए() के बाद foo लिखने के बाद, इसे foo-> तैयार तैयार लिखने की जरूरत है, वास्तव में आखिरी है, अन्यथा अन्य धागे foo-> जल्दी तैयार हो सकते हैं और गलत मान प्राप्त कर सकते हैं x/y/z। तो हम foo-> तैयार पर write_release
का उपयोग करते हैं, जैसा ऊपर बताया गया है, प्रभावी रूप से लिखने वाली कतार 'फ्लैश' करता है (एक्स, वाई, जेड सुनिश्चित कर रहा है) फिर कतार में तैयार = सही अनुरोध जोड़ता है। और फिर बार = 13 अनुरोध जोड़ता है। ध्यान दें कि चूंकि हमने अभी रिलीज बाधा का उपयोग किया है (पूर्ण नहीं) बार = 13 तैयार होने से पहले लिखा जा सकता है। लेकिन हमें परवाह नहीं है! यानी हम मानते हैं कि बार साझा डेटा नहीं बदल रहा है।
अब थ्रेडबी() को यह जानने की जरूरत है कि जब हम 'तैयार' कहते हैं तो हम वास्तव में तैयार हैं। तो हम read_acquire(foo->ready)
करते हैं। यह पढ़ा पढ़ा कतार में जोड़ा जाता है, फिर कतार फिसल जाती है। ध्यान दें कि w = some_global
अभी भी कतार में हो सकता है। तो foo-> तैयार some_global
से पहले पढ़ा जा सकता है। लेकिन फिर, हमें परवाह नहीं है, क्योंकि यह महत्वपूर्ण डेटा का हिस्सा नहीं है कि हम इस बारे में बहुत सावधान हैं। हम किस बारे में परवाह करते हैं foo-> x/y/z है। इसलिए उन्हें फ्लश/मार्कर प्राप्त करने के बाद पढ़ने की कतार में जोड़ा जाता है, यह गारंटी देता है कि वे केवल foo-> तैयार पढ़ने के बाद पढ़े जाते हैं।
ध्यान दें, यह आमतौर पर एक म्यूटेक्स/क्रिटिकलसेक्शन/आदि को लॉक करने और अनलॉक करने के लिए उपयोग की जाने वाली सटीक समान बाधाएं होती है। (यानी लॉक() पर अधिग्रहण, अनलॉक() पर रिलीज)।
तो,
मैं बहुत यकीन है कि यह (यानी अधिग्रहण/रिलीज) वास्तव में एमएस डॉक्स क्या कहते हैं पढ़ने के लिए होता है (और सी # में 'अस्थिर' चर का/लिखते एमएस सी के लिए वैकल्पिक रूप से ++ हूँ, लेकिन यह गैर मानक है)। सहित http://msdn.microsoft.com/en-us/library/aa645755(VS.71).aspx देखें "एक अस्थिर पढ़ा है" अर्थ विज्ञान के अधिग्रहण ", वह यह है कि यह स्मृति के सभी संदर्भ है कि यह बाद हो से पहले होने की गारंटी है ..."
मुझे लगता है कि जावा में एक ही है, हालांकि मैं परिचित नहीं हूँ। मुझे संदेह है कि यह बिल्कुल वही है, क्योंकि आपको आमतौर पर पढ़ने-प्राप्त/लिखने-रिलीज की तुलना में अधिक गारंटी की आवश्यकता नहीं होती है।
आपके प्रश्न में जब आप सोचते हैं कि यह वास्तव में रिश्तेदार आदेश के बारे में है तो आप सही रास्ते पर थे - आप केवल ऑर्डरिंग पीछे थे (यानी "जो मान पढ़े जाते हैं वे कम से कम अद्यतित होते हैं बाधा से पहले पढ़ता है? "- नहीं, अवरोधक महत्वहीन होने से पहले पढ़ता है, इसके बाद बाधा के बाद पढ़ा जाता है जो लिखने के लिए विपरीत होता है)।
और कृपया ध्यान दें, जैसा कि बताया गया है, रीडॉर्डिंग दोनों पढ़ने और लिखने पर होता है, इसलिए केवल एक थ्रेड पर बाधा का उपयोग करना और अन्य काम नहीं करेगा। यानी एक लेखन-रिलीज पढ़ने-अधिग्रहण के बिना पर्याप्त नहीं है। यानी यदि आप इसे सही क्रम में लिखते हैं, तो भी गलत आदेश में पढ़ा जा सकता है यदि आपने लिखने की बाधाओं के साथ पढ़ने के लिए पढ़ने की बाधाओं का उपयोग नहीं किया है।
और आखिरकार, ध्यान दें कि लॉक-फ्री प्रोग्रामिंग और सीपीयू मेमोरी आर्किटेक्चर वास्तव में उससे अधिक जटिल हो सकते हैं, लेकिन अधिग्रहण/रिलीज के साथ चिपकने से आपको बहुत दूर मिल जाएगा।
क्या इससे कोई फर्क नहीं पड़ता कि write_release और read_acquire संदर्भ एक ही तैयार चर है? या आप दोनों के लिए अलग डमी चर का उपयोग कर सकते हैं? लगता है कि मूल्य का कोई उद्देश्य नहीं है। –
सिंक्रनाइज़ करने की कोशिश कर रहे थ्रेड के लिए समान चर का उपयोग करना आवश्यक है। जैसे कि आपको उसी म्यूटेक्स का उपयोग करने या सामान्य थ्रेडिंग में लॉक करने की आवश्यकता होती है। मेरे धागा ए/बी उदाहरण में, हम यह सुनिश्चित करना चाहते हैं कि foo-> x, y, z foo-> तैयार होने से पहले लिखा गया है (अन्यथा कोई वास्तव में तैयार होने से पहले 'तैयार == सत्य' देख सकता है)। पढ़ने की तरफ, आप तैयार होने से पहले x, y, z को नहीं पढ़ना चाहते हैं, इसलिए आपको foo-> पर read_acquire की आवश्यकता है ताकि यह सुनिश्चित किया जा सके कि CPU x, y, z को पुन: व्यवस्थित नहीं करता है ' अगर (foo-> तैयार) '। यदि आपकी बाधाएं विभिन्न डमी चर पर थीं, तो आपके पास सिंक-पॉइंट नहीं होगा। – tony