2009-04-15 21 views
12

मैं अभी भी उलझन में हूँ ... जब हम इस तरह की कुछ बात लिखें:क्या लॉक() {} संसाधन को लॉक करता है, या क्या यह कोड का एक टुकड़ा लॉक करता है?

Object o = new Object(); 
var resource = new Dictionary<int , SomeclassReference>(); 

... और उस o ताला जबकि resource तक पहुँचने कोड के दो ब्लॉकों है ...

//Code one 
lock(o) 
{ 
    // read from resource  
} 

//Code two 
lock(o) 
{ 
    // write to resource 
} 

अब, यदि मेरे पास दो धागे हैं, तो एक थ्रेड निष्पादन कोड जो resource से पढ़ता है और इसके लिए एक और लेखन, मैं resource को लॉक करना चाहता हूं, जैसे कि इसे पढ़ा जा रहा है, लेखक को प्रतीक्षा करना होगा (और इसके विपरीत - अगर यह लिखा जा रहा है, पाठकों को इंतजार करना होगा)। क्या लॉक निर्माण मेरी मदद करेगा? ... या मुझे कुछ और इस्तेमाल करना चाहिए?

(मैं इस उदाहरण के प्रयोजनों के लिए Dictionary उपयोग कर रहा हूँ, लेकिन हो सकता है कुछ भी)

दो मामलों मैं विशेष रूप को लेकर चिंतित हूं रहे हैं:

  1. दो धागे एक ही पंक्ति पर अमल करने की कोशिश कर रहा कोड की
  2. दो धागे समान संसाधन दोनों की स्थिति में

विल lock मदद पर काम करने की कोशिश?

+0

@SilverHorse: अपना संपादन पर stomping के लिए खेद है - पीठ में एक टैग को जोड़ने के लिए गया था और नहीं पता था कि आप इस बीच में संपादित चाहते हैं! – Shog9

उत्तर

12

अन्य सभी उत्तर आपके कोड उदाहरण को संबोधित करते हैं, इसलिए मैं आपको शीर्षक में प्रश्न का उत्तर देने का प्रयास करूंगा।

एक लॉक वास्तव में सिर्फ एक टोकन है। जो भी टोकन है वह बोलने के लिए मंच ले सकता है। इस प्रकार जिस ऑब्जेक्ट पर आप लॉक कर रहे हैं उस संसाधन के साथ स्पष्ट कनेक्शन नहीं है जिसे आप सिंक्रनाइज़ करने का प्रयास कर रहे हैं। जब तक सभी पाठक/लेखक एक ही टोकन पर सहमत होते हैं, यह कुछ भी हो सकता है।

किसी ऑब्जेक्ट को लॉक करने का प्रयास करते समय (यानी किसी ऑब्जेक्ट पर Monitor.Enter पर कॉल करके) रनटाइम जांचता है कि लॉक पहले से ही थ्रेड द्वारा आयोजित किया गया है या नहीं। यदि ऐसा होता है तो लॉक को लॉक करने का प्रयास करने वाला थ्रेड निलंबित कर दिया जाता है, अन्यथा यह लॉक और आय निष्पादित करने के लिए प्राप्त करता है।

जब लॉक रखने वाला थ्रेड लॉक स्कोप से बाहर निकलता है (यानी Monitor.Exit पर कॉल करता है), लॉक जारी किया जाता है और कोई प्रतीक्षा धागा अब लॉक प्राप्त कर सकता है। जब तक आप की जरूरत है, लेकिन अब नहीं

  • लॉक:

    अंत में चीजों की एक जोड़ी मन के बारे में ताले में रखने के लिए।

  • यदि आप lock कीवर्ड के बजाय Monitor.Enter/Exit का उपयोग करते हैं, तो finally ब्लॉक में Exit पर कॉल करना सुनिश्चित करें ताकि लॉक को अपवाद के मामले में भी जारी किया जा सके।
  • ऑब्जेक्ट को लॉक करने के लिए एक्सपोज़ करना, यह लॉकिंग और कब लॉक करने का एक अवलोकन प्राप्त करना कठिन बनाता है। आदर्श रूप से सिंक्रनाइज़ किए गए संचालन को encapsulated किया जाना चाहिए।
+1

यह समझ में नहीं आया "ऑब्जेक्ट को लॉक करने के लिए एक्सपोज़ करना लॉकिंग और कौन सा है इसका अवलोकन प्राप्त करना मुश्किल हो जाता है। आदर्श रूप से सिंक्रनाइज़ किए गए ऑपरेशन को" धन्यवाद –

+0

यदि लॉकिंग के लिए उपयोग की जाने वाली ऑब्जेक्ट प्रकार के बाहर पहुंच योग्य है, तो यह कौन लॉकिंग की पहचान करने के लिए कठिन हो जाता है। दूसरी ओर यदि सभी लॉकिंग encapsulated है, तो आप आसानी से लॉकिंग का एक सिंहावलोकन प्राप्त कर सकते हैं। –

+0

यह स्पष्ट नहीं है। तुम्हारा मतलब ऑब्जेक्ट 'ओ' है कि मैंने कूड़े का इस्तेमाल सख्ती से एक प्रकार के भीतर किया है? –

0

और यह मानना ​​चाहिए कि आपके पास केवल एक प्रक्रिया शामिल है। यदि आप चाहते हैं कि एक से अधिक प्रक्रियाओं में काम करना चाहते हैं तो आप "म्यूटेक्स" का उपयोग करना चाहेंगे।

ओह, और "ओ" ऑब्जेक्ट, एक सिंगलटन होना चाहिए या लॉक की आवश्यकता होने पर हर जगह घूमना चाहिए, क्योंकि वास्तव में लॉक किया जा रहा है वह वस्तु है और यदि आप एक नया बनाते हैं, तो वह नया नहीं होगा अभी तक बंद कर दिया।

2

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

+0

दो मामलों ... 1) दो कोड का एक ही लाइन पर अमल करने की कोशिश कर thredas 2) दो समान संसाधन पर काम करने के लिए दोनों की स्थिति में मदद को लॉक कर देंगे –

5

हां, लॉक का उपयोग करना सही तरीका है। आप किसी ऑब्जेक्ट को लॉक कर सकते हैं, लेकिन जैसा कि अन्य उत्तरों में उल्लिखित है, आपके संसाधन पर लॉक करना शायद सबसे आसान और सुरक्षित है।

हालांकि, आप कंसुरेंसी ओवरहेड को कम करने के लिए, केवल एक लॉक के बजाय पढ़ने/लिखने वाली लॉक जोड़ी का उपयोग करना चाह सकते हैं।

इसके लिए तर्क यह है कि यदि आपके पास केवल एक धागा लेखन है, लेकिन कई धागे पढ़ रहे हैं, तो आप एक अन्य पढ़ाई ऑपरेशन को अवरुद्ध करने के लिए एक पठन ऑपरेशन नहीं चाहते हैं, लेकिन केवल एक पठन लिखना या इसके विपरीत।

अब, मैं एक जावा लड़का हूं, इसलिए आपको सी # में लागू करने के लिए सिंटैक्स बदलना होगा और कुछ दस्तावेज़ खोदना होगा, लेकिन rw-locks जावा में मानक समवर्ती पैकेज का हिस्सा हैं, ताकि आप कुछ लिख सकें :

public class ThreadSafeResource<T> implements Resource<T> { 
    private final Lock rlock; 
    private final Lock wlock; 
    private final Resource res; 

    public ThreadSafeResource(Resource<T> res) { 
     this.res = res; 
     ReentrantReadWriteLock rwl = new ReentrantReadWriteLock(); 
     this.rlock = rwl.readLock(); 
     this.wlock = rwl.writeLock(); 
    } 

    public T read() { 
     rlock.lock(); 
     try { return res.read(); } 
     finally { rlock.unlock(); } 
    } 

    public T write(T t) { 
     wlock.lock(); 
     try { return res.write(t); } 
     finally { wlock.unlock(); } 
    } 
} 

किसी एक सी # कोड नमूना के साथ आ सकते हैं ...

+0

किसी भी विचार कैसे की कोशिश कर रहा धागे कि पढ़ने लिखने लागू करने के लिए कर रहे हैं जोड़ी बंद करो? –

+3

संसाधन पर लॉक करना एक अच्छा विचार नहीं है यदि वह संसाधन अपने आंतरिक कोड के बाहर दिखाई दे रहा है। इससे डेडलॉक्स या दौड़ की स्थिति हो सकती है। यह अनुशंसा की जाती है कि आप उस परिदृश्य को रोकने के लिए एक निजी वस्तु को लॉक करें। –

+0

ठीक है, उस स्थिति में जब आप उस पर सामान कर रहे हों, तो आप अपने (ना-थ्रेड-सुरक्षित) संसाधन के साथ गड़बड़ करने के लिए अन्य समवर्ती-जागरूक कोड को रोकना चाहते हैं, इसलिए आप इसे लॉक करना चाहते हैं। – Varkhan

0

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

कुछ मामलों में एक अलग वस्तु का उपयोग उपयोगी हो सकता है, जैसे बाहरी संसाधनों तक पहुंच सिंक्रनाइज़ करना, लेकिन इस तरह के मामलों में यह ओवरहेड है।

2

ताला (ओ) {...} बयान इस के लिए संकलित किया गया है: अगर एक और धागा पहले से ही यह कहा है

Monitor.Enter(o) 
try { ... } 
finally { Monitor.Exit(o) } 

Monitor.Enter करने के लिए कॉल() धागा रोकेंगे। ऑब्जेक्ट पर मॉनिटर.एक्सिट() को अन्य थ्रेड के बाद इसे केवल अनब्लॉक कर दिया जाएगा।

2

दोनों स्थितियों में मदद बंद कर देगा? हां।

क्या लॉक() {} संसाधन लॉक करता है, या यह कोड का एक टुकड़ा लॉक करता है?

lock(o) 
{ 
    // read from resource  
} 

वाक्यात्मक चीनी

Monitor.Enter(o); 
try 
{ 
    // read from resource 
} 
finally 
{ 
    Monitor.Exit(o); 
} 

के लिए मॉनिटर वर्ग वस्तुओं है कि आप कोड के ब्लॉक के लिए उपयोग सिंक्रनाइज़ करने के लिए उपयोग कर रहे हैं का संग्रह रखती है। प्रत्येक सिंक्रनाइज़ किया जा रहा वस्तु के लिए, मॉनिटर रखता है:

  1. धागा है कि वर्तमान में समन्वयन करने वस्तु पर ताला धारण करने के लिए एक संदर्भ; यानी यह धागा की बारी को निष्पादित करने के लिए है।
  2. एक "तैयार" कतार - थ्रेड की सूची जो तब तक अवरुद्ध हो रही है जब तक उन्हें इस सिंक्रनाइज़िंग ऑब्जेक्ट के लिए लॉक नहीं दिया जाता है।
  3. ए 'प्रतीक्षा' कतार - धागे कि जब तक वे Monitor.Pulse (द्वारा "तैयार" कतार में ले जाया जाता है ब्लॉक की सूची) या Monitor.PulseAll()

तो, जब थ्रेड लॉक (ओ) कहता है, तो इसे ओ के तैयार कतार में रखा जाता है, जब तक इसे ओ लॉक नहीं दिया जाता है, उस समय यह अपने कोड को निष्पादित करता रहता है।

+0

निश्चित रूप से 'आखिरकार' होना चाहिए और निश्चित रूप से 'पकड़' नहीं होना चाहिए। नाइटपिक के लिए खेद है :) – Andy

+0

@ एंडी - हाँ। अद्यतन उत्तर – mbeckish

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