2012-05-23 24 views
10

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

वह कुछ इस तरह दिखना चाहिए:

//private static readonly lockObject = new Object(); 

public T GetCache<T>(string key, Func<T> valueFactory...) 
{ 

    // try to pull from cache here 

    lock (lockObject) // I don't want to use static object lock here because then every time a lock is performed, all cached objects in my site have to wait, regarding of the cache key. 
    { 
    // cache was empty before we got the lock, check again inside the lock 

    // cache is still empty, so retreive the value here 

    // store the value in the cache here 
    } 

    // return the cached value here 

} 
+0

आप क्या हासिल करने की कोशिश कर रहे हैं? ऐसा लगता है कि आप 2 प्रकार के ताले के बीच उलझन में हैं: यह सुनिश्चित करने के लिए लॉक करें कि केवल एक धागा कैश किए गए ऑब्जेक्ट को संपादित कर सकता है और कैश से जोड़ने/हटाने को सुनिश्चित करने के लिए लॉक सुरक्षित है। प्रति ऑब्जेक्ट लॉक जोड़ने से आपको यह सुनिश्चित करने में मदद मिलेगी कि केवल एक थ्रेड इसे बदल सकता है, लेकिन कैश से इसे जोड़ने/हटाने के साथ इसका कोई लेना-देना नहीं है (जो कार्यान्वयन आपने प्रदान नहीं किया है, लेकिन मुझे लगता है कि यह किसी प्रकार का होने वाला है शब्दकोश)। मुझे नहीं लगता कि आप कैश - संग्रह स्तर लॉक को वैसे भी खारिज कर सकते हैं। – YavgenyP

+0

मैं एएसपीनेट कैश का उपयोग कर रहा हूं ... इसलिए मुझे अपना खुद का शब्दकोश लागू करने की ज़रूरत नहीं है ... और मैं जोड़ने के लिए लॉक करने के बारे में बात कर रहा हूं ... मान लें कि 1000 लोगों ने एक ही समय में पृष्ठ का अनुरोध किया है, मैं चाहता हूं उनमें से केवल उनमें से एक ऑब्जेक्ट को कैश करने के लिए, और अन्य सभी इसका उपयोग करने के लिए ... – Amir

+0

आपको अभी भी अंतर्निहित संग्रह को लॉक करने की आवश्यकता है, न कि ऑब्जेक्ट। यदि आप सही ढंग से समझते हैं, तो आप यह करना चाहते हैं कि यह संग्रह इस संग्रह में मौजूद नहीं है या नहीं, और उसके बाद ही इसे जोड़ें। यदि आप .NET 4 का उपयोग कर रहे हैं, तो आप यह सुनिश्चित करने के लिए कि प्रत्येक कुंजी केवल एक बार जोड़ दी जाती है, आप अपने नए अवरुद्ध संग्रहों जैसे कि ConcurrentDictionary का उपयोग कर सकते हैं। – YavgenyP

उत्तर

1

यह मामला है कि आप mutex

public T GetCache<T>(string key, Func<T> valueFactory...) 
{ 
    // note here that I use the key as the name of the mutex 
    // also here you need to check that the key have no invalid charater 
    // to used as mutex name. 
    var mut = new Mutex(true, key); 

    try 
    { 
     // Wait until it is safe to enter. 
     mut.WaitOne(); 

     // here you create your cache 
    } 
    finally 
    { 
     // Release the Mutex. 
     mut.ReleaseMutex(); 
    } 
} 
+0

भले ही उसे किसी भी प्रकार की लॉक या सिंक ऑब्जेक्ट की आवश्यकता हो - उसे म्यूटेक्स का उपयोग क्यों करना चाहिए और मॉनिटर नहीं करना चाहिए? "म्यूटेक्स क्लास मॉनिटर क्लास से अधिक सिस्टम संसाधनों का उपयोग करता है" ([msdn] से (http://msdn.microsoft.com/en-us/library/hw29w7t1.aspx)) – YavgenyP

+1

@YavgenyP दो मुख्य कारण हैं: 1) इस धागा का उपयोग करने के लिए जाने वाले सभी धागे को लॉक करने के लिए, और केवल एक धागा। 2) नाम देने और कैश के केवल उसी हिस्से को लॉक करने के लिए और अनुरोध किए गए प्रत्येक कैश नहीं। - अब, मुझे नहीं पता कि उसे सिंक की जरूरत है या नहीं, मैं उसे करने के लिए गर्म हो जाता हूं और तर्क नहीं देता कि उसे जरूरत है या नहीं। – Aristos

0

नेट ConcurrentDictionary<TKey, TItem> इस लागू करता है का उपयोग आंतरिक रूप से प्रत्येक के लिए एक अलग ताला बनाने के द्वारा कुंजी हैश आइटम जोड़ों और निकासी को संसाधित करते समय भी, एक प्रासंगिक हैश को लॉक करने का लाभ होता है।

1

मुझे अभी LazyCache lib मिला है। हालांकि मैंने अभी तक उत्पादन में कोशिश नहीं की है।

IAppCache cache = new CachingService(); 
ComplexObject cachedResults = cache.GetOrAdd("uniqueKey", 
    () => methodThatTakesTimeOrResources()); 
+0

लिंक के लिए धन्यवाद - मैं इसे उत्पादन में उपयोग करता हूं और यह अच्छी तरह से काम करता है, लेकिन मुझे लगता है कि - मैंने इसे लिखा था। – alastairtree