2012-04-16 8 views
7

के साथ मॉनिटर। ट्राइंटर, मेरे पास एक ऐसी स्थिति है जहां परीक्षण के लिए, मैं केवल एक बार में अपना टाइमर विधि (FooMethod) चलाने के लिए चाहता हूं। नीचे दिए गए उदाहरण में, FooMethod को एक टाइमर के प्रतिनिधि के रूप में पास किया जाता है। इस वर्ग के कई ठोस उदाहरण हैं। मैंने सोचा कि _locker स्थिर बनाकर, FooMethod() का केवल एक उदाहरण एक समय में प्रक्रिया करेगा। लेकिन जब मैं ऐप चलाता हूं, तो कई थ्रेड एक समय में TryEnter() लाइन से पहले हो रहे हैं।जेनेरिक क्लास

इस प्रकार मैं प्रत्येक कक्षा को एक नए टाइमर में जोड़ रहा हूं। यह एक पाश में किया जाता है, प्रत्येक foo उदाहरण के लिए:

_timers.Add(new Timer(foo.FooMethod, null, 0, 10000)); 

और इस वर्ग कि विधि है कि:

public class Foo<T> 
{ 
    private static readonly object _locker = new object(); 

    public void FooMethod(object stateInfo) 
    { 
     // Don't let threads back up; just get out 
     if (!Monitor.TryEnter(_locker)) { return; } 

     try 
     { 
      // Logic here 
     } 
     finally 
     { 
      Monitor.Exit(_locker); 
     } 
    } 
} 

नोट: आम तौर पर, _locker स्थिर नहीं है, मैं पूरा करने का मौका मिलने से पहले एक ही थ्रेड विधि में प्रवेश नहीं करना चाहता हूं। मैंने इसे परीक्षण के लिए स्थिर में बदल दिया।

मेरा पहला विचार यह है कि शायद यह काम नहीं कर रहा है क्योंकि कक्षा सामान्य है? और यह कि प्रत्येक ठोस वर्ग वास्तव में अपनी कक्षा है और वे _locker चर साझा नहीं करते हैं? क्या यह सच है? यदि यह सच है तो मेरे पास ठोस वर्गों को _locker चर साझा करना चाहिए? क्या मुझे किसी अन्य वर्ग में एक स्थिर _locker चर जोड़ने की आवश्यकता है जिस पर फूज़ का उपयोग है?

+0

बहुत ही रोचक और अच्छी तरह से पूछे जाने वाले प्रश्न। +1 – spender

+2

ध्यान दें कि एक ही थ्रेड * एक लॉक फिर से दर्ज कर सकता है (लेकिन केवल तभी कुछ रिकर्सन है)।यही ताले के लिए हैं: एक ही संसाधन का उपयोग करने से * अलग * धागे को रोकना। – phoog

+0

@ स्पेंडर धन्यवाद। और फूग, मैं समझता हूँ। स्थैतिक चर के साथ मेरा लक्ष्य एक ही समय में उस विधि को संसाधित करने से कई धागे को रोकने के लिए था। लेकिन यह काम नहीं कर रहा है। –

उत्तर

7

क्या मुझे किसी अन्य वर्ग में पर एक स्थिर _locker चर जोड़ने की आवश्यकता है, जिसे फ़ूज़ तक पहुंच है?

हां।

प्रत्येक Foo<T> प्रकार बंद T तर्कों के साथ, इसकी अपनी स्थिर _locker ऑब्जेक्ट है। आप फू को बेस क्लास से प्राप्त कर सकते हैं, और वहां स्थिर वस्तु डाल सकते हैं। फिर, सभी प्रकार एक ही उदाहरण का उपयोग करेंगे।

6

शायद

public class Foo 
{ 
    protected static readonly object _locker = new object(); 
} 

public class Foo<T> : Foo 
{ 
    public void FooMethod(object stateInfo) 
    {   
     if (!Monitor.TryEnter(_locker)) { return; } 

     try 
     { 
      // Logic here 
     } 
     finally 
     { 
      Monitor.Exit(_locker); 
     } 
    } 
} 
+0

धन्यवाद। यह हल करने के लिए एक शानदार तरीका का एक अच्छा उदाहरण है। –

0

कृपया गैर सामान्य प्रकार के रूप में इस वर्ग के हैं। यह आपकी ज़रूरत का मकसद करेगा।

public class Foo 
{ 
    private static readonly object _locker = new object(); 

    public void FooMethod(object stateInfo) 
    { 
     // Don't let threads back up; just get out 
     if (!Monitor.TryEnter(_locker)) { return; } 

     try 
     { 
      // Logic here 
     } 
     finally 
     { 
      Monitor.Exit(_locker); 
     } 
    } 
} 
+0

लेकिन मेरे पास इस वर्ग को सामान्य कारण के रूप में सामान्य है। मैं इसे पूर्ववत नहीं करना चाहता हूं। –

2

आप सही हैं। कोड में संदर्भित प्रत्येक अद्वितीय प्रकार T सीएलआर को Foo<T> के लिए एक नया ठोस प्रकार उत्पन्न करने का कारण बनता है और प्रत्येक के पास स्थिर सदस्यों का अपना सेट होता है।

आप निम्न को देखने के लिए अपने कोड को पुन: स्थापित कर सकते हैं। यह कई मान्य भिन्नताओं में से एक है।

public class Foo 
{ 
    private static readonly object _locker = new object(); 

    public void FooMethod(object stateInfo) 
    { 
     // Don't let threads back up; just get out 
     if (!Monitor.TryEnter(_locker)) { return; } 

     try 
     { 
      // Logic here 
     } 
     finally 
     { 
      Monitor.Exit(_locker); 
     } 
    } 
} 

public class Foo<T> 
{ 
    public void FooMethod(object stateInfo) 
    { 
     Foo.FooMethod(stateInfo); 
    } 
} 

इसके अलावा, ध्यान रखें कि आप एक अनंत period साथ टाइमर शुरू कर सकते हैं एक बार से अधिक को क्रियान्वित करने के कॉलबैक को रोकने के लिए रहते हैं। टाइमर फिर से कतारबद्ध करने के लिए FooMethod के अंत में Change पर कॉल करें। चूंकि आपके पास एक बार में कई टाइमर चल रहे हैं, फिर भी आपके पास FooMethod के साथ-साथ कई समवर्ती निष्पादन होंगे, लेकिन कम से कम अब प्रति टाइमर केवल एक सक्रिय कॉल होगा। यह वही नहीं है जो आपने पूछा था, लेकिन मैंने सोचा कि मैं इसे किसी भी तरह से इंगित करूंगा।

_timers.Add(new Timer(foo.FooMethod, _timers.Count, 10000, Timeout.Infinite)); 

public class Foo<T> 
{ 
    public void FooMethod(object stateInfo) 
    { 
     try 
     { 
      // Logic here 
     } 
     finally 
     { 
      int index = (int)stateInfo; 
      _timers[index].Change(10000, Timeout.Infinite); 
     } 
    } 
} 
+0

अच्छी चीजें। धन्यवाद, ब्रायन! –

+0

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