2011-05-27 10 views
7

मैं पदानुक्रमित संगठित संसाधनों तक पहुंच प्रबंधित करने के लिए पदानुक्रमित रूप से व्यवस्थित पढ़ने/लिखने वाले ताले की एक श्रृंखला रखने के लिए सक्षम प्रणाली की तलाश में हूं। यदि एक सबट्री लिखने के लिए बंद कर दिया गया है, तो जब तक इसे जारी नहीं किया जाता है तब तक पूरे उपट्री में कोई अन्य लॉक प्राप्त नहीं किया जाना चाहिए; इसी प्रकार, एक उपट्री में एक लिखने की तालाब को माता-पिता में लॉक करना बंद कर देना चाहिए।पदानुक्रमित पुनर्वित्त पढ़ने/लिखने के लिए जावा में उपयोग करने की क्या रणनीति है?

यहाँ विचारों मैं विचार कर रहे थे इस प्रकार हैं:

  • Apache Commons Transaction का प्रयोग करें। अनजाने में, परियोजना को मार्च 2008 से अपडेट नहीं किया गया है और अनधिकृत रूप से समाप्त कर दिया गया है। कुछ एपीआई दस्तावेज़ यह इंगित करते थे कि आने वाले संस्करण (1.3 या 2.0) में some kind of hierarchical locking शामिल होगा, लेकिन स्रोत कहीं भी नहीं पाए जाते हैं और ऐसा लगता है कि हम अब उनके एसवीएन भंडार तक नहीं पहुंच सकते हैं।

  • ReentrantReadWriteLocks की एक श्रृंखला का उपयोग करें, जिसे मैं श्रेणीबद्ध रूप से व्यवस्थित करता हूं। मैं कोई समवर्ती विशेषज्ञ नहीं हूं, और मैं खुद ही ऐसा करने से थोड़ा डरता हूं। शुरुआती विचार यह इंगित करते थे कि इससे पहले कि मैं एक उप-लॉक को लॉक करने का प्रयास कर सकूं, मुझे ReentrantReadWriteLock एस के प्रबंधन की पूरी संरचना पर बाहरी लॉक का उपयोग करना होगा - ताकि लॉक को रिलीज़ करने के लिए भी मुझे उपयोग करना होगा बाहरी ताला ... java.util.concurrent और java.util.concurrent.atomic से

  • उपयोग कक्षाओं का सबसे प्रभावशाली तरीका की तुलना में मैं ReentrantReadWriteLock रों की एक श्रृंखला के साथ कर सकता मेरी श्रेणीबद्ध ताला लागू करने के लिए।

मैं उस अंतिम सड़क पर जाने के लिए तैयार हूं, लेकिन मुझे आश्चर्य हुआ कि कोई भी बाहरी पुस्तकालय नहीं ढूंढ पाएगा जो इस समस्या को बेहतर तरीके से हल करेगा। तो:

  • क्या मुझे कुछ स्पष्ट समाधान याद आया है?
  • या यह समस्या ठीक से हल करने के लिए विशेष रूप से कठिन है?
+0

'परमाणु' से दूर रहें, यह हास्यास्पद रूप से समझने और कार्यान्वित करने के लिए सूक्ष्म है। – toto2

+1

आपका दूसरा समाधान सही लगता है। जब आप नोड को लॉक करना चाहते हैं तो आपको वैश्विक लॉक प्राप्त करने की आवश्यकता है, ताकि आप जांच सकें कि उस नोड के किसी भी बच्चे को लॉक नहीं किया गया है, और यह भी कि उसके किसी भी पैरेंट को लॉक नहीं किया गया है। – toto2

+0

वैसे, कॉमन्स लेनदेन [उपलब्ध] है (http://commons.apache.org/transaction/download_transaction.cgi), लेकिन मुझे नहीं पता कि यह आपके लिए उपयोगी है या नहीं। – toto2

उत्तर

3

मुझे नहीं पता कि मैं आपके प्रश्न को अच्छी तरह से समझता हूं, जैसा कि आप कहते हैं कि जब आप लिखने के लिए उपट्री लॉक करते हैं, तो पूरी संरचना बंद हो जाती है। तो, सरल समाधान पूरे ढांचे के लिए एक आरडब्ल्यू लॉक होना है।

वैसे, java.util.concurrent.atomic आपको आरडब्ल्यू ताले के पेड़ से अधिक मदद नहीं करेगा।


आप में सक्षम ताला भाई बहन independly होना चाहते हैं, तो आप दूसरा समाधान (ताले की एक पेड़ जहां प्रत्येक नोड इसके जनक के लिए एक संदर्भ है) के साथ जा सकते हैं।

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

ऊपर वर्णित लॉक एक विशेष लॉक है। (पढ़ने-लिखने की ताले का दूसरा नाम है साझा अनन्य ताले)

साझा ताले जोड़ने के लिए, प्रत्येक नोड भी एक परमाणु पूर्णांक संकेत की जरूरत है: यह सकारात्मक है कि अगर, अप्रत्यक्ष लिखने बंद कर दिया बच्चों की संख्या; यदि यह ऋणात्मक है कि नोड को पढ़ने के लिए कितनी बार पढ़ा गया है। इसके अलावा, माता-पिता पर नए लेखन ताले हासिल करने से बचने के लिए नोड और उसके माता-पिता को लॉक किया जाएगा।

छद्म कोड:

Node { 
    // fields 
    parent: Node 
    lock: RWLock 
    count: AtomicInteger 
} 

public boolean trylocktree(node: Node, exclusive: boolean) { 
    if (exclusive) { 
     return trylocktree_ex(node, true); 
    } else { 
     return trylocktree_sh(node); 
    } 
} 
private boolean switch_count(i: AtomicInteger, diff: int) { 
    // adds diff to i if the sign of i is the same as the sign of diff 
    while (true) { 
     int v = i.get(); 
     if (diff > 0 ? v < 0 : v > 0) 
      return false; 
     if (i.compareAndSet(v, v + diff)) 
      return true; 
    } 
} 
private boolean trylocktree_ex(node: Node, writing: boolean) { 
    // check if a node is read-locked 
    if (!switch_count(node.count, 1)) 
     return false; 
    // lock using the lock type passed as an arg 
    if (!node.lock(writing).trylock()) { 
     node.count--; 
     return false; 
    } 
    // read-lock every parent 
    if (!trylocktree_ex(node.parent, false)) { 
     node.count-- 
     node.lock(writing).unlock(); 
     return false; 
    } 
    return true; 
} 
private boolean trylocktree_sh(node: Node) { 
    // mark as shared-locked subtree 
    if (!switch_count(node.count, -1)) 
     return false; 
    // get shared-lock on parents 
    if (!readlock_recursively(node)) { 
     node.count++; 
     return false; 
    } 
    return true; 
} 
private boolean readlock_recursively(node: Node) { 
    if (!node.lock(false).trylock()) 
     return false; 
    if (!readlock_recursively(node.parent)) { 
     node.lock(false).unlock(); 
     return false; 
    } 
    return true; 
} 

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

संपादित करें: ताला-पढ़ने के लिए/एक पेड़

+0

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

+0

मैंने जो लॉक वर्णित किया है वह इस तरह की संरचना के लिए पुनर्विक्रय लॉक का कार्यान्वयन है, न कि एक पठन-लिखने वाला ताला। मैं एक पठन/लिखने के लॉक समाधान पर काम कर रहा हूं। – Kru

+0

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

0

मैं अपने खुद के समाधान के लिए जाने के लिए और कलन विधि प्रारंभिक बिंदु के रूप अपाचे Apache Commons Transaction Algorithm द्वारा दिए गए लगेगा लिखने-लॉक करने के लिए कोड जोड़ा। आप एक ReentrantReadWriteLock का उपयोग कर सकते हैं हालांकि आम तौर पर यह लॉक एक निर्माता के पैटर्न को बेहतर बनाता है-कई पाठक केस जो हो सकता है कि आप जो खोज रहे हैं वह हो। ऐसा लगता है कि आपका लॉक एक नियमित पुनर्विक्रेता म्यूटेक्स लॉक की तरह है।

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