गतिरोध और livelock में क्या अंतर है?


323

क्या कोई कृपया उदाहरणों (कोड के) के साथ समझा सकता है कि गतिरोध और लाइवलॉक के बीच क्या अंतर है ?


जवाबों:


398

Http://en.wikipedia.org/wiki/Deadlock से लिया गया :

समवर्ती कंप्यूटिंग में, एक गतिरोध वह स्थिति होती है, जिसमें क्रियाओं के समूह का प्रत्येक सदस्य, किसी अन्य सदस्य द्वारा लॉक भेजने के लिए प्रतीक्षा कर रहा होता है

एक लाइवलॉक गतिरोध के समान है, सिवाय इसके कि लाइवलॉक में शामिल प्रक्रियाओं की स्थिति एक दूसरे के संबंध में लगातार बदलती रहती है, कोई भी प्रगति नहीं करता है। लाइवलॉक संसाधन भुखमरी का एक विशेष मामला है; सामान्य परिभाषा केवल यह बताती है कि एक विशिष्ट प्रक्रिया प्रगति नहीं कर रही है।

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

लाइवलॉक कुछ एल्गोरिदम के साथ एक जोखिम है जो गतिरोध का पता लगाता है और पुनर्प्राप्त करता है। यदि एक से अधिक प्रक्रिया होती है, तो गतिरोध का पता लगाने वाले एल्गोरिदम को बार-बार ट्रिगर किया जा सकता है। यह सुनिश्चित करने से बचा जा सकता है कि केवल एक प्रक्रिया (यादृच्छिक रूप से या प्राथमिकता से चुनी गई) कार्रवाई करती है।


8
मुझे यह पहले से ही मिल गया, लेकिन उनके पास ऐसे उदाहरण नहीं हैं जैसा कि आप देख सकते हैं, वैसे भी धन्यवाद
मैकबुक

61
मैं एक कोड उदाहरण प्रदान नहीं करूंगा, लेकिन दो प्रक्रियाओं पर विचार करें जो प्रत्येक संसाधन के लिए प्रतीक्षा कर रहा है लेकिन गैर-अवरुद्ध तरीके से प्रतीक्षा कर रहा है। जब प्रत्येक सीखता है कि वे जारी नहीं रख सकते हैं तो वे अपने आयोजित संसाधन को सोते हैं और 30 सेकंड के लिए सो जाते हैं, फिर वे अपने मूल संसाधन को पुनः प्राप्त करते हैं, इसके बाद संसाधन को दूसरी प्रक्रिया में ले जाने की कोशिश करते हैं, फिर छोड़ दिया जाता है, फिर से प्राप्त किया जाता है। चूंकि दोनों प्रक्रियाएं (केवल बुरी तरह) सामना करने की कोशिश कर रही हैं, यह एक लाइवलॉक है।
महिंद्रा

4
क्या आप मुझे एक ही उदाहरण दे सकते हैं, लेकिन गतिरोध के साथ, अग्रिम धन्यवाद
मैक

32
एक गतिरोध का उदाहरण बहुत आसान है ... दो प्रक्रियाओं ए और बी को मान लें, और प्रत्येक संसाधन आर 1 और संसाधन आर 2 चाहता है। मान लें कि A को (या पहले से ही) r1 है, और B को (या पहले से ही) r2 प्राप्त है। अब प्रत्येक संसाधन को दूसरे समय के बिना प्राप्त करने का प्रयास करते हैं। A अवरुद्ध है क्योंकि B में r2 है, और B अवरुद्ध है क्योंकि A में r1 है। प्रत्येक प्रक्रिया अवरुद्ध है और इस प्रकार संसाधन को अन्य वांछितों को जारी नहीं किया जा सकता है, जिससे गतिरोध पैदा होता है।
माह

2
ट्रांसेक्शनल मेमोरी के संदर्भ में गतिरोध और
लाइवलॉक

78

Livelock

एक धागा अक्सर दूसरे धागे की कार्रवाई के जवाब में कार्य करता है। यदि दूसरे धागे की कार्रवाई दूसरे धागे की कार्रवाई की प्रतिक्रिया भी है, तो लाइवलॉक का परिणाम हो सकता है।

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

लाइवलॉक और गतिरोध के बीच मुख्य अंतर यह है कि धागे अवरुद्ध नहीं होने जा रहे हैं, इसके बजाय वे एक-दूसरे को लगातार जवाब देने की कोशिश करेंगे।

इस छवि में, दोनों वृत्त (धागे या प्रक्रियाएँ) बाएँ और दाएँ घुमाकर दूसरे को स्थान देने का प्रयास करेंगे। लेकिन वे आगे नहीं बढ़ सकते।

यहां छवि विवरण दर्ज करें



1
इस चीज का एक नाम है। एक कठबोली शब्द शायद, लेकिन अभी भी: schlumperdink : P
जॉन रेड

64

यहां सभी सामग्री और उदाहरण हैं

ऑपरेटिंग सिस्टम: इंटर्नल्स और डिज़ाइन सिद्धांत
विलियम स्टालिंग्स
8। संस्करण

गतिरोध : एक ऐसी स्थिति जिसमें दो या दो से अधिक प्रक्रियाएं आगे नहीं बढ़ पाती हैं क्योंकि प्रत्येक व्यक्ति कुछ करने के लिए एक दूसरे की प्रतीक्षा कर रहा है।

उदाहरण के लिए, दो प्रक्रियाओं, पी 1 और पी 2 और दो संसाधनों, आर 1 और आर 2 पर विचार करें। मान लीजिए कि प्रत्येक प्रक्रिया को अपने कार्य का हिस्सा करने के लिए दोनों संसाधनों तक पहुंच की आवश्यकता होती है। तब निम्न स्थिति होना संभव है: ओएस आर 1 को पी 2, और आर 2 को पी 1 प्रदान करता है। प्रत्येक प्रक्रिया दो संसाधनों में से एक की प्रतीक्षा कर रही है। न तो उस संसाधन को जारी करेगा जो पहले से ही मालिक है जब तक कि उसने दूसरे संसाधन का अधिग्रहण नहीं किया है और दोनों संसाधनों की आवश्यकता वाले फ़ंक्शन का प्रदर्शन किया है। दो प्रक्रियाएं गतिरोध हैं

Livelock : एक ऐसी स्थिति जिसमें दो या दो से अधिक प्रक्रियाएं लगातार किसी भी उपयोगी कार्य को किए बिना अन्य प्रक्रियाओं (तों) में परिवर्तन के जवाब में अपने राज्यों को लगातार बदलती रहती हैं:

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

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

परिशिष्ट ए - सामंजस्य में विषय

डेडलॉक उदाहरण

यदि दोनों प्रक्रियाओं ने अपने झंडे को सच में सेट किया है, तो या तो पहले बयान को निष्पादित किया है, तो प्रत्येक सोचेंगे कि दूसरे ने अपने महत्वपूर्ण खंड में प्रवेश किया है, जिससे गतिरोध पैदा हो गया है।

/* PROCESS 0 */
flag[0] = true;            // <- get lock 0
while (flag[1])            // <- is lock 1 free?
    /* do nothing */;      // <- no? so I wait 1 second, for example
                           // and test again.
                           // on more sophisticated setups we can ask
                           // to be woken when lock 1 is freed
/* critical section*/;     // <- do what we need (this will never happen)
flag[0] = false;           // <- releasing our lock

 /* PROCESS 1 */
flag[1] = true;
while (flag[0])
    /* do nothing */;
/* critical section*/;
flag[1] = false;

लाइवलॉक उदाहरण

/* PROCESS 0 */
flag[0] = true;          // <- get lock 0
while (flag[1]){         
    flag[0] = false;     // <- instead of sleeping, we do useless work
                         //    needed by the lock mechanism
    /*delay */;          // <- wait for a second
    flag[0] = true;      // <- and restart useless work again.
}
/*critical section*/;    // <- do what we need (this will never happen)
flag[0] = false; 

/* PROCESS 1 */
flag[1] = true;
while (flag[0]) {
    flag[1] = false;
    /*delay */;
    flag[1] = true;
}
/* critical section*/;
flag[1] = false;

[...] घटनाओं के निम्नलिखित अनुक्रम पर विचार करें:

  • P0 ध्वज को सेट करता है [0] सच करने के लिए।
  • P1 ध्वज को सेट करता है [1] सच करने के लिए।
  • P0 ध्वज की जाँच करता है [1]।
  • P1 ध्वज की जाँच करता है [को ०]।
  • P0 झंडे को सेट करता है [0] झूठे को।
  • P1 झंडे को सेट करता है [1] झूठे को।
  • P0 ध्वज को सेट करता है [0] सच करने के लिए।
  • P1 ध्वज को सेट करता है [1] सच करने के लिए।

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

अब किताब से सामग्री नहीं।

और पालक के बारे में क्या?

स्पिनलॉक ओएस लॉक तंत्र की लागत से बचने की एक तकनीक है। आमतौर पर आप ऐसा करेंगे:

try
{
   lock = beginLock();
   doSomething();
}
finally
{
   endLock();
}

एक समस्या तब सामने आने लगती है जब beginLock()लागत बहुत अधिक होती है doSomething()। बहुत ही एक्सटर्स्ड शब्दों में, कल्पना करें कि जब beginLockलागत 1 सेकंड होती है, लेकिन doSomethingलागत केवल 1 मिलीसेकंड होती है।

इस मामले में यदि आपने 1 मिली सेकंड इंतजार किया, तो आप 1 सेकंड के लिए बाधा बनने से बचेंगे।

beginLockइतना खर्च क्यों होगा? यदि लॉक मुफ़्त है, तो बहुत खर्च नहीं होता है ( https://stackoverflow.com/a/49712993/5397116 देखें ), लेकिन अगर लॉक मुफ़्त नहीं है, तो OS आपके धागे को "फ्रीज़" करेगा, आपको जगाने के लिए एक तंत्र तैयार करेगा। जब ताला मुक्त हो जाता है, और फिर भविष्य में आपको फिर से जगाता है।

यह सब लॉक की जाँच करने वाले कुछ लूपों की तुलना में बहुत अधिक महंगा है। यही कारण है कि कभी-कभी "स्पिनलॉक" करना बेहतर होता है।

उदाहरण के लिए:

void beginSpinLock(lock)
{
   if(lock) loopFor(1 milliseconds);
   else 
   {
     lock = true;
     return;
   }

   if(lock) loopFor(2 milliseconds);
   else 
   {
     lock = true;
     return;
   }

   // important is that the part above never 
   // cause the thread to sleep.
   // It is "burning" the time slice of this thread.
   // Hopefully for good.

   // some implementations fallback to OS lock mechanism
   // after a few tries
   if(lock) return beginLock(lock);
   else 
   {
     lock = true;
     return;
   }
}

यदि आपका कार्यान्वयन सावधान नहीं है, तो आप लॉक सिस्टम पर सभी सीपीयू खर्च करके लाइवलॉक पर गिर सकते हैं।

और देखें:

https://preshing.com/20120226/roll-your-own-lightweight-mutex/
क्या मेरा स्पिन लॉक कार्यान्वयन सही और इष्टतम है?

सारांश :

गतिरोध : वह स्थिति जहाँ कोई प्रगति नहीं करता, कुछ भी नहीं कर रहा (सो रहा है, प्रतीक्षा कर रहा है ..)। सीपीयू का उपयोग कम होगा;

लाइवलॉक : ऐसी स्थिति जहां कोई भी प्रगति नहीं करता है, लेकिन सीपीयू लॉक तंत्र पर खर्च किया जाता है और आपकी गणना पर नहीं;

भुखमरी: वह स्थिति जहां एक प्रचारक को कभी भी दौड़ने का मौका नहीं मिलता; शुद्ध दुर्भाग्य से या इसकी संपत्ति में से कुछ (कम प्राथमिकता, उदाहरण के लिए);

स्पिनलॉक : लागत से बचने की तकनीक ताला मुक्त होने की प्रतीक्षा कर रही है।


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

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

स्पिनलॉक के बारे में जोड़ने के लिए धन्यवाद, आपके अनुसार स्पिनलॉक एक तकनीक है और यू ने इसे भी उचित ठहराया और मैं समझ गया। लेकिन उस प्राथमिकता उलटा समस्या के बारे में क्या है जब एक प्रक्रिया पी 1 क्रिटिकल सेक्शन में है और अन्य उच्च प्राथमिकता प्रक्रिया पी 2 को पूर्व निर्धारित पी 1 प्राप्त होता है तो इस मामले में पी 2 पी 2 के साथ है और हमारा सिंक्रोनाइज़ेशन तंत्र पी 1 के साथ है। इसे स्पिनलॉक कहा जाता है क्योंकि P1 तैयार अवस्था में है और P2 रन अवस्था में है। यहां स्पिनलॉक एक समस्या है। क्या मैं चीजों को सही कर रहा हूं? मैं पेचीदगियों को ठीक से समझ नहीं पा रहा हूँ। कृपया मदद करें
विनय यादव

मेरा सुझाव है कि आप अपनी समस्या को और स्पष्ट रूप से बताते हुए एक और प्रश्न तैयार करें। अब, यदि आप "यूजर स्पेस" में हैं, और पी 1 एक अनन्त लूप के साथ लागू किए गए स्पिनलॉक के साथ संरक्षित एक महत्वपूर्ण सत्र के अंदर है और इसके प्रीमेप्टेड है; तब P2 इसे दर्ज करने की कोशिश करेगा, wil विफल होगा और इसके सभी समय-स्लाइस को जला देगा। आपने एक लाइवलॉक (एक CPU 100% पर होगा) बनाया। (एक बुरा उपयोग स्पिनलॉक के साथ एक सिंक IO की रक्षा के लिए होगा। आप इस उदाहरण को आसानी से आज़मा सकते हैं) "कर्नेल स्पेस" पर शायद यह नोट आपकी मदद कर सकता है: lxr.linux.no/linux+v3.6.6/Dadmentation/…
डैनियल फ्रेडेरिको ने लीट

स्पष्टीकरण के लिए बहुत-बहुत धन्यवाद। वैसे भी, आपका जवाब दूसरों के विपरीत काफी वर्णनात्मक और मददगार था
विनय यादव

13

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

LIVELOCK लाइवलॉक की स्थिति तब उत्पन्न हो सकती है जब दो या दो से अधिक कार्य निर्भर करते हैं और कुछ संसाधन का उपयोग करते हुए एक परिपत्र निर्भरता की स्थिति पैदा करते हैं, जहाँ वे कार्य हमेशा चलते रहते हैं, इस प्रकार सभी निचले प्राथमिकता स्तर के कार्यों को चलने से रोकते हैं (ये निम्न प्राथमिकता वाले कार्य एक स्थिति को भुखमरी कहते हैं)


यदि 'livelocked' कार्य संसाधन मध्यस्थता प्रोटोकॉल का अनुसरण कर रहे हैं, जिसमें 'backoff' देरी शामिल है, और परिणामस्वरूप अपना अधिकांश समय नींद की अवस्था में बिताते हैं, तो अन्य कार्य भूखे नहीं रहेंगे।
ग्राग्गो

8

हो सकता है कि ये दो उदाहरण आपको एक गतिरोध और लाइवलॉक के बीच के अंतर को दर्शाते हैं:


गतिरोध के लिए जावा-उदाहरण:

import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class DeadlockSample {

    private static final Lock lock1 = new ReentrantLock(true);
    private static final Lock lock2 = new ReentrantLock(true);

    public static void main(String[] args) {
        Thread threadA = new Thread(DeadlockSample::doA,"Thread A");
        Thread threadB = new Thread(DeadlockSample::doB,"Thread B");
        threadA.start();
        threadB.start();
    }

    public static void doA() {
        System.out.println(Thread.currentThread().getName() + " : waits for lock 1");
        lock1.lock();
        System.out.println(Thread.currentThread().getName() + " : holds lock 1");

        try {
            System.out.println(Thread.currentThread().getName() + " : waits for lock 2");
            lock2.lock();
            System.out.println(Thread.currentThread().getName() + " : holds lock 2");

            try {
                System.out.println(Thread.currentThread().getName() + " : critical section of doA()");
            } finally {
                lock2.unlock();
                System.out.println(Thread.currentThread().getName() + " : does not hold lock 2 any longer");
            }
        } finally {
            lock1.unlock();
            System.out.println(Thread.currentThread().getName() + " : does not hold lock 1 any longer");
        }
    }

    public static void doB() {
        System.out.println(Thread.currentThread().getName() + " : waits for lock 2");
        lock2.lock();
        System.out.println(Thread.currentThread().getName() + " : holds lock 2");

        try {
            System.out.println(Thread.currentThread().getName() + " : waits for lock 1");
            lock1.lock();
            System.out.println(Thread.currentThread().getName() + " : holds lock 1");

            try {
                System.out.println(Thread.currentThread().getName() + " : critical section of doB()");
            } finally {
                lock1.unlock();
                System.out.println(Thread.currentThread().getName() + " : does not hold lock 1 any longer");
            }
        } finally {
            lock2.unlock();
            System.out.println(Thread.currentThread().getName() + " : does not hold lock 2 any longer");
        }
    }
}

नमूना उत्पादन:

Thread A : waits for lock 1
Thread B : waits for lock 2
Thread A : holds lock 1
Thread B : holds lock 2
Thread B : waits for lock 1
Thread A : waits for lock 2

एक लाइवलॉक के लिए जावा-उदाहरण:


import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class LivelockSample {

    private static final Lock lock1 = new ReentrantLock(true);
    private static final Lock lock2 = new ReentrantLock(true);

    public static void main(String[] args) {
        Thread threadA = new Thread(LivelockSample::doA, "Thread A");
        Thread threadB = new Thread(LivelockSample::doB, "Thread B");
        threadA.start();
        threadB.start();
    }

    public static void doA() {
        try {
            while (!lock1.tryLock()) {
                System.out.println(Thread.currentThread().getName() + " : waits for lock 1");
                Thread.sleep(100);
            }
            System.out.println(Thread.currentThread().getName() + " : holds lock 1");

            try {
                while (!lock2.tryLock()) {
                    System.out.println(Thread.currentThread().getName() + " : waits for lock 2");
                    Thread.sleep(100);
                }
                System.out.println(Thread.currentThread().getName() + " : holds lock 2");

                try {
                    System.out.println(Thread.currentThread().getName() + " : critical section of doA()");
                } finally {
                    lock2.unlock();
                    System.out.println(Thread.currentThread().getName() + " : does not hold lock 2 any longer");
                }
            } finally {
                lock1.unlock();
                System.out.println(Thread.currentThread().getName() + " : does not hold lock 1 any longer");
            }
        } catch (InterruptedException e) {
            // can be ignored here for this sample
        }
    }

    public static void doB() {
        try {
            while (!lock2.tryLock()) {
                System.out.println(Thread.currentThread().getName() + " : waits for lock 2");
                Thread.sleep(100);
            }
            System.out.println(Thread.currentThread().getName() + " : holds lock 2");

            try {
                while (!lock1.tryLock()) {
                    System.out.println(Thread.currentThread().getName() + " : waits for lock 1");
                    Thread.sleep(100);
                }
                System.out.println(Thread.currentThread().getName() + " : holds lock 1");

                try {
                    System.out.println(Thread.currentThread().getName() + " : critical section of doB()");
                } finally {
                    lock1.unlock();
                    System.out.println(Thread.currentThread().getName() + " : does not hold lock 1 any longer");
                }
            } finally {
                lock2.unlock();
                System.out.println(Thread.currentThread().getName() + " : does not hold lock 2 any longer");
            }
        } catch (InterruptedException e) {
            // can be ignored here for this sample
        }
    }
}

नमूना उत्पादन:

Thread B : holds lock 2
Thread A : holds lock 1
Thread A : waits for lock 2
Thread B : waits for lock 1
Thread B : waits for lock 1
Thread A : waits for lock 2
Thread A : waits for lock 2
Thread B : waits for lock 1
Thread B : waits for lock 1
Thread A : waits for lock 2
Thread A : waits for lock 2
Thread B : waits for lock 1
...

दोनों उदाहरण थ्रेड्स को अलग-अलग क्रम में ताले को जलाने के लिए मजबूर करते हैं। जबकि गतिरोध दूसरे लॉक का इंतजार करता है, लाइवलॉक वास्तव में इंतजार नहीं करता है - यह सख्त मौका प्राप्त करने के बिना लॉक को प्राप्त करने की कोशिश करता है। हर कोशिश में सीपीयू साइकिल की खपत होती है।


कोड अच्छा है। लेकिन लाइव-लॉक का उदाहरण अच्छा नहीं है। क्या कोई थ्रेड किसी मान पर अवरोधित है या मान में परिवर्तन के लिए मतदान वैचारिक रूप से भिन्न नहीं है। लाइव-लॉक को बेहतर ढंग से चित्रित करने के लिए एक आसान बदलाव यह है कि थ्रेड्स ए और बी में वे ताले हैं जब उन्हें एहसास होता है कि उन्हें दूसरा लॉक नहीं मिल सकता है जिसकी उन्हें आवश्यकता है। फिर वे एक दूसरे के लिए सोते हैं, ताला को फिर से खोलते हैं जो उनके पास मूल रूप से था, फिर एक दूसरे के लिए सोते हैं और दूसरे लॉक को फिर से हासिल करने की कोशिश करते हैं। तो प्रत्येक के लिए चक्र होगा: 1) अधिग्रहण-मेरा, 2) नींद, 3) अन्य हासिल करने की कोशिश करो और असफल, 4) रिहाई-मेरा, 5) नींद, 6) दोहराएं।
CognizantApe

1
मुझे संदेह है कि क्या आप जिन लाइव-लॉक के बारे में सोचते हैं, वे वास्तव में लंबे समय से मौजूद हैं कि वे परेशानी पैदा करते हैं। जब आप हमेशा सभी ताले छोड़ देते हैं तो आप तब पकड़ते हैं जब आप अगले लॉक को आवंटित नहीं कर सकते हैं, गतिरोध (और लाइव-लॉक) स्थिति "होल्ड और प्रतीक्षा" गायब है क्योंकि वास्तव में अब कोई इंतजार नहीं है। ( en.wikipedia.org/wiki/Deadlock )
mmirwaldt

वास्तव में मृत लॉक की स्थिति गायब है क्योंकि ये लाइव लॉक हैं जिनकी हम चर्चा कर रहे हैं। मैंने जो उदाहरण दिया है , वह दिए गए मानक हॉलवे के उदाहरण के समान है: geeksforgeeks.org/deadlock-starvation-and-livelock , en.wikibooks.org/wiki/Operating_System_Design_Concurrency/… , docs.oracle.com/javase/tutorial/essential/ / संगामिति / ...
कॉग्निजेंट

0

कल्पना कीजिए कि आपने थ्रेड ए और थ्रेड बी हैं। वे दोनों synchronisedएक ही वस्तु पर हैं और इस ब्लॉक के अंदर एक वैश्विक चर है जो वे दोनों अपडेट कर रहे हैं;

static boolean commonVar = false;
Object lock = new Object;

...

void threadAMethod(){
    ...
    while(commonVar == false){
         synchornized(lock){
              ...
              commonVar = true
         }
    }
}

void threadBMethod(){
    ...
    while(commonVar == true){
         synchornized(lock){
              ...
              commonVar = false
         }
    }
}

इसलिए, जब थ्रेड ए whileलूप में प्रवेश करता है और लॉक रखता है, तो वह वही करता है जो उसे करना है और सेट करना commonVarहै true। तब थ्रेड बी, में आता है में प्रवेश करती है whileपाश और के बाद से commonVarहै trueअब, यह ताला पकड़ करने में सक्षम हो सकता है। ऐसा करता है, synchronisedब्लॉक निष्पादित करता है , और commonVarवापस सेट करता है false। अब, थ्रेड ए को फिर से नई सीपीयू विंडो मिलती है, यह लूप छोड़ने के बारे में थीwhile लेकिन थ्रेड बी ने इसे वापस सेट कर दिया है false, इसलिए यह चक्र फिर से दोहराता है। धागे कुछ करते हैं (इसलिए वे पारंपरिक अर्थों में अवरुद्ध नहीं हैं) लेकिन बहुत ज्यादा कुछ नहीं के लिए।

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


अच्छा उदाहरण है। यह भी दिखाता है कि क्यों आपको हमेशा समवर्ती संदर्भ में परमाणु को पढ़ना और लिखना चाहिए। यदि लूप्स सिंक्रोनाइज़ ब्लॉकों के अंदर होते हैं तो ऊपर एक मुद्दा नहीं होगा।
CognizantApe
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.