2012-01-09 9 views
5

मैं सीएमयू स्फिंक्स स्पीच रिकग्नाइज़र लाइब्रेरी (Link to source) का उपयोग कर रहा हूं जो synchronized ब्लॉक का कुछ उपयोग करता है। RecognizerTask सेमल्टीथ्रेडेड शुद्धता: सिंक्रनाइज़ ब्लॉक का उपयोग

एक उदाहरण ब्लॉक:

बग:: RecognizerTask.mailbox पर तुल्यकालन व्यर्थ प्रयास में गार्ड को

Event mailbox; 

[...] 

public void start() { 
    synchronized (this.mailbox) { 
     this.mailbox.notifyAll(); 
     this.mailbox = Event.START; 
    } 
} 

कोड किसी भी समस्याओं के बिना काम करता है, तथापि BugFinder यह चेतावनी देता है यह

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

private Long myNtfSeqNbrCounter = new Long(0); 
private Long getNotificationSequenceNumber() { 
    Long result = null; 
    synchronized(myNtfSeqNbrCounter) { 
     result = new Long(myNtfSeqNbrCounter.longValue() + 1); 
     myNtfSeqNbrCounter = new Long(result.longValue()); 
    } 
    return result; 
} 

ईमानदारी से कहूं तो मैं काफी बग विवरण समझ में नहीं आता है और क्या माना जाता है कि इस मामले में गलत हो सकता है। एक वैश्विक चर नहीं है? और यदि नहीं, तो मैं कोड कैसे सुधार सकता हूं?

/संपादन:

Event todo = Event.NONE; 
     synchronized (this.mailbox) { 
      todo = this.mailbox; 
      /* If we're idle then wait for something to happen. */ 
      if (state == State.IDLE && todo == Event.NONE) { 
       try { 
        //Log.d(getClass().getName(), "waiting"); 
        this.mailbox.wait(); 
        todo = this.mailbox; 
        //Log.d(getClass().getName(), "got" + todo); 
       } catch (InterruptedException e) { 
        /* Quit main loop. */ 
        //Log.e(getClass().getName(), "Interrupted waiting for mailbox, shutting down"); 
        todo = Event.SHUTDOWN; 
       } 
      } 
      /* Reset the mailbox before releasing, to avoid race condition. */ 
      this.mailbox = Event.NONE; 
     } 

इस कोड को वास्तव में एक synchronized बयान के रूप में अच्छी तरह से उपयोग कर रहा है: यह केवल हिस्सा है जहां Event.wait() कहा जाता है। क्या इसका उपयोग करने के लिए बिल्कुल समझ में आता है?

उत्तर

3

मुझे नहीं लगता कि यह आपके मामले में लागू होता है।

synchronized (this.mailbox) { 
    this.mailbox.wait();   
} 

जिसका अर्थ है कि अन्य धागा अधिसूचित होने की प्रतीक्षा कर, जबकि ताला त्यागना होगा: आप notifyAll() के लिए एक कॉल जिसका अर्थ है एक मिलान wait() कॉल है कि वहाँ अन्य धागे की कोड में कहीं है।

आपका कोड निरीक्षक शायद रेखा से उलझन में है:

this.mailbox = Event.START; 

जिसका अर्थ है कि आप एक साथ इस वस्तु को संशोधित किया जा सकता है, इस तरह के हैं कि अगर एक और धागा this.mailbox पर ताला पाने के लिए प्रयास करता है, यह एक अलग वस्तु देखेंगे ।

  1. this.mailbox विश्व स्तर पर दिखाई
  2. संदर्भों के प्रदान करती है परमाणु कर रहे हैं
  3. ताला एक बाड़ उत्पन्न

सभी धागे तुल्यकालन की एक अद्यतन दृश्य होना चाहिए: हालांकि, मुझे लगता है कि जब से लगता है ऑब्जेक्ट हर समय।

+0

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

+0

आपके उत्तर के लिए बहुत बहुत धन्यवाद! कृपया मेरा अद्यतन प्रश्न देखें - क्या आप पूरी तरह से 'सिंक्रनाइज़' को हटाने की सलाह देंगे? – Force

+1

दरअसल आप ऐसा नहीं कर सकते क्योंकि प्रतीक्षा करने या सूचित करने/सूचित करने के लिए कॉल एक ऑब्जेक्ट पर एक ही ऑब्जेक्ट पर सिंक्रनाइज़ किए गए ब्लॉक के अंदर होना चाहिए। – Tudor

3

सिंक्रनाइज़ ब्लॉक mailbox द्वारा निर्दिष्ट ऑब्जेक्ट के लिए आपके मामले में दिए गए ऑब्जेक्ट के लिए लॉक "कैप्चर" करता है। एक बार जब आप किसी भिन्न ऑब्जेक्ट को इंगित करने के लिए वेरिएबल mailbox बदलते हैं, तो अन्य थ्रेड बिना किसी समस्या के इस ऑब्जेक्ट के लॉक को "कैप्चर" कर सकते हैं, क्योंकि यह नहीं लिया जाता है।

ध्यान दें कि लॉक ऑब्जेक्ट्स के लिए है, न कि संदर्भों के लिए!

अब, निम्नलिखित [छद्म कोड] विचार:

synchronised (myObject) { 
    myObject = new Object(); 
    i += 5; //assume i is an instance variable 
} 

व्यावहारिक रूप से कोई लॉक यहाँ है! प्रत्येक थ्रेड लॉक ब्लॉक में एक नई वस्तु बना रहा है, और मैं संशोधन को सिंक्रनाइज़ नहीं किया गया है!

+1

यही कारण है कि हमें अंतिम वस्तु बनाने और लॉकिंग के लिए इसका उपयोग करने की आवश्यकता है। –

+0

आपके उत्तर के लिए बहुत बहुत धन्यवाद! कृपया मेरा अद्यतन प्रश्न देखें - क्या आप पूरी तरह से 'सिंक्रनाइज़' को हटाने की सलाह देंगे? – Force

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