सामान्य रूप से री-प्रवेश लॉक और अवधारणा क्या है?


91

मैं हमेशा उलझन में रहता हूं। क्या कोई समझाएगा कि अलग-अलग संदर्भों में रेंटेंट का क्या मतलब है? और आप रीएन्स्ट्रेंट बनाम गैर-रेन्ट्रेंट का उपयोग क्यों करना चाहेंगे?

प्राइथ्रेड (पॉज़िक्स) कहो कि वे आदिम हैं, वे फिर से प्रवेश कर रहे हैं या नहीं? उनका उपयोग करते समय क्या नुकसान से बचा जाना चाहिए?

म्यूटेक्स फिर से प्रवेश है?

जवाबों:


157

री-एंट्रेंट लॉकिंग

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

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

यदि कोड साझा स्थिति पर निर्भर करता है जिसे इसके निष्पादन के बीच में अद्यतन किया जा सकता है तो यह फिर से प्रवेश नहीं है, कम से कम यदि यह अद्यतन इसे तोड़ नहीं सकता है।

फिर से प्रवेश लॉकिंग के लिए एक उपयोग मामला

पुनः प्रवेश करने वाले लॉक के लिए एक आवेदन का (कुछ सामान्य और आकस्मिक) उदाहरण हो सकता है:

  • आपके पास एक एल्गोरिथम शामिल करने के लिए कुछ संगणना है जो एक ग्राफ को खींचता है (शायद इसमें चक्र के साथ)। ट्रैवर्सल चक्र के कारण या एक ही नोड के लिए कई पथों के कारण एक ही नोड पर एक से अधिक बार आ सकता है।

  • डेटा संरचना समवर्ती पहुंच के अधीन है और किसी कारण से, किसी अन्य थ्रेड द्वारा अद्यतन किया जा सकता है। दौड़ की स्थितियों के कारण संभावित डेटा भ्रष्टाचार से निपटने के लिए आपको अलग-अलग नोड्स को लॉक करने में सक्षम होना चाहिए। किसी कारण से (शायद प्रदर्शन) आप विश्व स्तर पर संपूर्ण डेटा संरचना को लॉक नहीं करना चाहते हैं।

  • आपकी गणना आपके द्वारा देखे गए नोड्स के बारे में पूरी जानकारी नहीं रख सकती है, या आप एक डेटा संरचना का उपयोग कर रहे हैं जो अनुमति नहीं देता है 'सवालों के जवाब देने से पहले मैं यहां हूं'।

    इस स्थिति का एक उदाहरण दिज्क्स्ट्रा के एल्गोरिथ्म का एक सरल कार्यान्वयन होगा जिसमें एक बाइनरी हीप या एक ब्रेडथ-फर्स्ट सर्च के रूप में कार्यान्वित प्राथमिकता कतार एक सरल लिंक्ड सूची का उपयोग कतार के रूप में किया जाता है। इन मामलों में, मौजूदा सम्मिलन के लिए कतार को स्कैन करना O (N) है और आप इसे हर पुनरावृत्ति पर नहीं करना चाहते हैं।

इस स्थिति में, आपके द्वारा पहले से प्राप्त किए गए ताले को ट्रैक करना महंगा है। यह मानते हुए कि आप नोड स्तर पर लॉकिंग करना चाहते हैं, फिर से प्रवेश करने वाला लॉकिंग तंत्र यह बताने की आवश्यकता को कम करता है कि आपने पहले नोड का दौरा किया है या नहीं। आप केवल नेत्रहीन रूप से नोड को लॉक कर सकते हैं, शायद कतार से पॉप करने के बाद इसे अनलॉक कर रहे हैं।

पुन: प्रवेश म्यूटेक्स

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

IIRC POSIX थ्रेड्स एपीआई री-एंट्रेंट और नॉन री-एंट्रेंट म्यूटेक्स का विकल्प प्रदान करता है।


2
हालांकि ऐसी स्थितियों को आमतौर पर वैसे भी टाला जाना चाहिए, क्योंकि यह गतिरोध आदि से भी बचने के लिए कठिन बनाता है। थ्रेडिंग वैसे भी बिना किसी संदेह के पर्याप्त है, जैसे कि आपको पहले ही लॉक मिल गया हो।
जॉन स्कीट

+1, उस मामले पर भी विचार करें जहां ताला पुनर्वितरित नहीं है, यदि आप सावधान नहीं हैं तो आप खुद को ब्लॉक कर सकते हैं। इसके अलावा सी में, आपके पास अन्य भाषाओं को लॉक सुनिश्चित करने के लिए अन्य भाषाओं के समान तंत्र नहीं है क्योंकि यह एक्वायर्ड है। इससे बड़ी समस्याएं पैदा हो सकती हैं।
user7116

1
यह सटीक गीत है जो कल मेरे साथ हुआ: मैंने एक विचार में फिर से प्रवेश के मुद्दे को नहीं लिया और 5 घंटे के लिए गतिरोध को समाप्त कर दिया ...
वाहन

@ जोंन स्कीट - मुझे लगता है कि संभवत: ऐसी स्थितियाँ हैं (ऊपर कुछ मेरे द्वारा देखा गया उदाहरण देखें) जहां तालों का ट्रैक रखना प्रदर्शन या अन्य विचारों के कारण अव्यावहारिक है।
कंसर्नडऑफटुनब्रिजवेल्स

21

री-एंट्रेंट लॉक आपको एक विधि लिखने की सुविधा देता है Mजो संसाधन पर एक लॉक लगाता है Aऔर फिर Mपुनरावर्ती या कोड से कॉल करता है जो पहले से ही एक लॉक रखता है A

एक गैर-री-एंट्रेंट लॉक के साथ, आपको 2 संस्करणों की आवश्यकता होगी M, जिसमें से एक लॉक और एक ऐसा नहीं है, और सही को कॉल करने के लिए अतिरिक्त तर्क।


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

यह एक वास्तविक वर्ल्ड समस्या नहीं होनी चाहिए। यह दानेदार लॉकिंग के बारे में अधिक है और यह कि एक थ्रेड खुद को बंद नहीं करेगा।
हेंक होल्टरमैन

16

इस ट्यूटोरियल में रेन्ट्रेंट लॉक बहुत अच्छी तरह से वर्णित है ।

ग्राफ़ में उदाहरण, किसी ग्राफ को ट्रेस करने के बारे में उत्तर की तुलना में बहुत कम है। एक रीवेंट्रेंट लॉक बहुत सरल मामलों में उपयोगी है।


3

पुनरावर्ती म्यूटेक्स का क्या और क्यों को स्वीकार किए गए उत्तर में वर्णित ऐसी जटिल चीज नहीं होना चाहिए।

नेट के आसपास कुछ खुदाई के बाद मैं अपनी समझ को लिखना चाहूंगा।


सबसे पहले, आपको यह महसूस करना चाहिए कि म्यूटेक्स के बारे में बात करते समय , बहु धागा अवधारणाएं निश्चित रूप से शामिल होती हैं। (सिंक्रनाइज़ेशन के लिए म्यूटेक्स का उपयोग किया जाता है। यदि मुझे केवल मेरे कार्यक्रम में 1 धागा है तो मुझे म्यूटेक्स की आवश्यकता नहीं है)


दूसरे, आपको एक सामान्य म्यूटेक्स और एक पुनरावर्ती म्यूटेक्स के अंतर को जानना चाहिए

APUE से उद्धृत :

(एक पुनरावर्ती म्यूटेक्स) एक म्यूटेक्स प्रकार है जो एक ही धागे को पहले अनलॉक किए बिना इसे कई बार लॉक करने की अनुमति देता है।

मुख्य अंतर यह है कि एक ही थ्रेड के भीतर , एक पुनरावर्ती लॉक को अनलॉक करने के लिए गतिरोध उत्पन्न नहीं होता है, न ही थ्रेड को ब्लॉक करें।

इसका मतलब यह है कि पुनरावर्ती ताला कभी गतिरोध का कारण बनता है?
नहीं, यह अभी भी सामान्य म्यूटेक्स के रूप में गतिरोध पैदा कर सकता है यदि आपने इसे एक धागे में बिना अनलॉक किए इसे बंद कर दिया है, और इसे अन्य थ्रेड्स में लॉक करने का प्रयास करें।

प्रमाण के रूप में कुछ कोड देखते हैं।

  1. गतिरोध के साथ सामान्य म्यूटेक्स
#include <pthread.h>
#include <stdio.h>

pthread_mutex_t lock;


void * func1(void *arg){
    printf("thread1\n");
    pthread_mutex_lock(&lock);
    printf("thread1 hey hey\n");

}


void * func2(void *arg){
    printf("thread2\n");
    pthread_mutex_lock(&lock);
    printf("thread2 hey hey\n");
}

int main(){
    pthread_mutexattr_t lock_attr;
    int error;
//    error = pthread_mutexattr_settype(&lock_attr, PTHREAD_MUTEX_RECURSIVE);
    error = pthread_mutexattr_settype(&lock_attr, PTHREAD_MUTEX_DEFAULT);
    if(error){
        perror(NULL);
    }

    pthread_mutex_init(&lock, &lock_attr);

    pthread_t t1, t2;

    pthread_create(&t1, NULL, func1, NULL);
    pthread_create(&t2, NULL, func2, NULL);

    pthread_join(t2, NULL);

}

उत्पादन:

thread1
thread1 hey hey
thread2

आम गतिरोध उदाहरण, कोई समस्या नहीं है।

  1. गतिरोध के साथ पुनरावर्ती mutex

बस इस लाइन को अनकंफर्ट करें
error = pthread_mutexattr_settype(&lock_attr, PTHREAD_MUTEX_RECURSIVE);
और दूसरे को कमेंट करें।

उत्पादन:

thread1
thread1 hey hey
thread2

हां, पुनरावर्ती म्यूटेक्स भी गतिरोध पैदा कर सकता है।

  1. सामान्य म्यूटेक्स, एक ही धागे में फिर से
#include <pthread.h>
#include <stdio.h>
#include <unistd.h>

pthread_mutex_t lock;


void func3(){
    printf("func3\n");
    pthread_mutex_lock(&lock);
    printf("func3 hey hey\n");
}

void * func1(void *arg){
    printf("thread1\n");
    pthread_mutex_lock(&lock);
    func3();
    printf("thread1 hey hey\n");

}


void * func2(void *arg){
    printf("thread2\n");
    pthread_mutex_lock(&lock);
    printf("thread2 hey hey\n");
}

int main(){
    pthread_mutexattr_t lock_attr;
    int error;
//    error = pthread_mutexattr_settype(&lock_attr, PTHREAD_MUTEX_RECURSIVE);
    error = pthread_mutexattr_settype(&lock_attr, PTHREAD_MUTEX_DEFAULT);
    if(error){
        perror(NULL);
    }

    pthread_mutex_init(&lock, &lock_attr);

    pthread_t t1, t2;

    pthread_create(&t1, NULL, func1, NULL);
    sleep(2); 
    pthread_create(&t2, NULL, func2, NULL);

    pthread_join(t2, NULL);

}

उत्पादन:

thread1
func3
thread2

डेडलॉक इन thread t1, इन func3
(मैं sleep(2)यह देखने के लिए आसान बनाने के लिए उपयोग करता हूं कि गतिरोध सबसे पहले अनलॉक करने के कारण होता है func3)

  1. पुनरावर्ती म्यूटेक्स, एक ही धागे में फिर से

फिर से, पुनरावर्ती म्यूटेक्स लाइन को अनइंस्टॉल करें और दूसरी लाइन पर टिप्पणी करें।

उत्पादन:

thread1
func3
func3 hey hey
thread1 hey hey
thread2

डेडलॉक इन thread t2, इन func2। देख? func3खत्म हो जाता है और बाहर निकल जाता है, पुन: लोड करने से थ्रेड ब्लॉक नहीं होता है और न ही गतिरोध होता है।


तो, आखिरी सवाल, हमें इसकी आवश्यकता क्यों है?

पुनरावर्ती फ़ंक्शन के लिए (बहु-थ्रेडेड प्रोग्राम में कहा जाता है और आप कुछ संसाधन / डेटा की रक्षा करना चाहते हैं)।

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

स्वीकृत उत्तर से एक उदाहरण देखें पुनरावर्ती म्यूटेक्स का उपयोग कब करें?

विकिपीडिया, पुनरावर्ती म्यूटेक्स को बहुत अच्छी तरह से समझाता है। निश्चित रूप से एक पढ़ने के लिए लायक है। विकिपीडिया: Reentrant_mutex

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.