5

सी # में, निम्न कोड (this पेज से) lazily एक धागा सुरक्षित रास्ते में एक सिंगलटन वर्ग का दृष्टांत के लिए इस्तेमाल किया जा सकता है:डेल्फी में "डबल-चेक लॉकिंग" को कैसे लागू किया जाना चाहिए?

class Foo { 
     private volatile Helper helper = null; 
     public Helper getHelper() { 
      if (helper == null) { 
       lock(this) { 
        if (helper == null) 
         helper = new Helper(); 
       } 
      } 
      return helper; 
     } 
    } 

क्या बराबर धागा सुरक्षित डेल्फी कोड हो सकता है?


लेख में यह भी डबल के साथ दो समस्याओं का उल्लेख है जावा में लॉक करना जाँच:

  • यह संभव है कि नई वस्तु से पहले सहायक संदर्भ नव निर्मित जिसका अर्थ है कि वस्तु पर बात करने के लिए किया जाता है का निर्माण किया है दो वस्तुओं बनाई गई हैं
  • यह संभव है कि सहायक संदर्भ स्मृति का एक ब्लॉक पर बात करने के लिए है, जबकि अभी भी वस्तु जिसका अर्थ है कि एक अधूरी ऑब्जेक्ट के संदर्भ लौटा दी जाएगी बनाया जा रहा है बना है

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

उत्तर

7

उपयोग System.TMonitor एक धागा सुरक्षित तरीका में वस्तु उदाहरण लॉक करने के लिए।

function TFoo.GetHelper(): THelper; 
begin 
    if not Assigned(FHelper) then 
    begin 
    System.MonitorEnter(Self); 
    try 
     if not Assigned(FHelper) then 
     FHelper := THelper.Create(); 
    finally 
     System.MonitorExit(Self); 
    end; 
    end; 
    Result := FHelper; 
end; 
Allen Bauer से Lock my object..., please! पर आगे के संदर्भ के लुक के लिए

। वास्तव में, प्रतिनिधि। मैं इस से इकट्ठा एलेन जाना चाहिए।

+1

मैं इसे बेहतर नहीं कह सकता था ;-) –

+0

मुझे यह महसूस हो रहा है कि इस कोड में कुछ आवश्यक है: सी # कार्यान्वयन निजी हेल्पर चर के लिए 'अस्थिर' कीवर्ड का उपयोग करता है। मुझे लगता है कि FHelper ** ** को 'थ्रेडवर 'के रूप में घोषित किया जाना चाहिए? – mjn

+0

थ्रेडवार के परिणामस्वरूप सभी धागे द्वारा साझा किए गए सिंगलटन की बजाय एक प्रति थ्रेड होगा। अस्थिर .net स्मृति मॉडल के कारण हो सकता है। लेकिन उपरोक्त कोड x86 पर सही है। –

2
बेशक

, यह हमेशा याद है कि Double-Checked Locking is Broken लायक है। यह समस्या x86 मेमोरी मॉडल पर लागू न होने के लिए बाहर निकलती है लेकिन भविष्य के लिए हमेशा ध्यान देने योग्य है। मुझे यकीन है कि कुछ बिंदु पर डेल्फी संस्करण होगा जो इस मुद्दे से पीड़ित स्मृति मॉडल के साथ एक मंच पर चलेगा।

Embarcadero interlocked तुलना/आदान प्रदान के साथ इस पद्धति का एक ताला मुक्त संस्करण का उपयोग शुरू कर दिया है। उदाहरण के लिए:

class function TEncoding.GetUnicode: TEncoding; 
var 
    LEncoding: TEncoding; 
begin 
    if FUnicodeEncoding = nil then 
    begin 
    LEncoding := TUnicodeEncoding.Create; 
    if InterlockedCompareExchangePointer(Pointer(FUnicodeEncoding), LEncoding, nil) <> nil then 
     LEncoding.Free; 
    end; 
    Result := FUnicodeEncoding; 
end; 

मुझे पता है यह नहीं प्रश्न का उत्तर है, लेकिन यह एक टिप्पणी में वास्तव में फिट नहीं था!

+0

डबल-चेक किए गए लॉकिंग * हमेशा * टूटा हुआ है? उल्लिखित आलेख में कहा गया है कि उपरोक्त सी # उदाहरण 'अपेक्षा के अनुसार काम करता है'। – mjn

+0

यह उपयोग में मेमोरी मॉडल पर निर्भर करता है। यह x86 पर काम करता है लेकिन मुझे x64 के बारे में निश्चित नहीं है। यह जावा पर टूटा हुआ है जिसका अपना मेमोरी मॉडल है। हालांकि यह बहुत जटिल है। –

+0

x86 और x64 एक ही 'मजबूत' मेमोरी मॉडल का उपयोग करते हैं, हालांकि Itanium http://igoro.com/archive/volatile-keyword-in-c-memory-model-explained/ – mjn

संबंधित मुद्दे