2011-08-14 31 views
5

मेरे पास एक ऐसा कार्य है जिसे मैं हर x सेकेंड का आह्वान करना चाहता हूं, लेकिन मैं इसे थ्रेड-सुरक्षित होना चाहता हूं।गैर-पुनर्वित्त टाइमर

जब मैं टाइमर बना रहा हूं तो क्या मैं इस व्यवहार को स्थापित कर सकता हूं? (मुझे कोई फर्क नहीं पड़ता कि मैं कौन सा .NET टाइमर उपयोग करता हूं, मैं बस इसे थ्रेड-सुरक्षित होना चाहता हूं)।

मुझे पता है कि मैं अपने कॉलबैक फ़ंक्शन के अंदर ताले लगा सकता हूं, लेकिन मुझे लगता है कि यह टाइमर स्तर में होने पर अधिक सुरुचिपूर्ण होगा।

मेरा कॉलबैक फ़ंक्शन, और पर्यावरण यूआई से संबंधित नहीं है।

[संपादित करें 1] मैं नहीं चाहता कि मेरे कॉलबैक फ़ंक्शन के अंदर एक से अधिक धागे हों।

[संपादित करें 2] मैं, टाइमर स्तर के अंदर ताला रखना चाहते हैं क्योंकि टाइमर जब मेरे कॉलबैक कॉल करने के लिए के लिए जिम्मेदार है, और यहाँ वहाँ एक विशेष स्थिति है जब मैं फोन करने के लिए नहीं करना चाहती है मेरी कॉलबैक फ़ंक्शन तो मुझे लगता है कि कॉल करने के लिए टाइमर की ज़िम्मेदारी है।

+2

यदि आपके पास पर्याप्त जानकारी नहीं देते ... अपने समारोह का उपयोग कर सकते कुछ भी कार्यक्रम तक पहुँचता है के किसी अन्य भाग करता है? यदि नहीं, तो यह पहले से ही थ्रेडसेफ (टाइमर के साथ और बिना) है ... यदि हां, तो टाइमर में थ्रेडस्फीटी के साथ कुछ भी नहीं है लेकिन आपको कुछ लॉक आदि का उपयोग करने की आवश्यकता है। – Yahia

+1

** ** आप लॉकिंग क्यों रखना चाहते हैं कॉलबैक फ़ंक्शन बिल्कुल ठीक है? –

+0

@ पॉल - मेरा संपादन देखें 2 – Delashmate

उत्तर

16

मैं अनुमान लगा रहा हूं, क्योंकि आपका प्रश्न पूरी तरह स्पष्ट नहीं है, कि आप यह सुनिश्चित करना चाहते हैं कि आपका टाइमर कॉलबैक संसाधित करते समय आपकी कॉलबैक दोबारा दर्ज नहीं कर सकता है, और आप इसे लॉक किए बिना करना चाहते हैं। आप इसे System.Timers.Timer का उपयोग करके प्राप्त कर सकते हैं और यह सुनिश्चित कर सकते हैं कि AutoReset संपत्ति गलत पर सेट है।इससे यह सुनिश्चित होगा कि आप, मैन्युअल रूप से प्रत्येक अंतराल पर टाइमर को गति प्रदान करने और इस प्रकार किसी भी reentrancy रोकने है:

public class NoLockTimer : IDisposable 
{ 
    private readonly Timer _timer; 

    public NoLockTimer() 
    { 
     _timer = new Timer { AutoReset = false, Interval = 1000 }; 

     _timer.Elapsed += delegate 
     { 
      //Do some stuff 

      _timer.Start(); // <- Manual restart. 
     }; 

     _timer.Start(); 
    } 

    public void Dispose() 
    { 
     if (_timer != null) 
     { 
      _timer.Dispose(); 
     } 
    } 
} 
+0

आप मेरी खोज में पूरी तरह से समझते हैं, और आपका समाधान पसंद करते हैं, मुझे आशा है कि यह व्यवहार टाइमर वर्ग में से एक के अंदर रखा गया है, लेकिन यह काफी अच्छा है .. – Delashmate

+0

यह वही है जो मैंने किया और यह बहुत अच्छा काम करता है। एफवाईआई- यदि आप किसी अज्ञात प्रतिनिधि का उपयोग नहीं करते हैं तो यह उदाहरण थोड़ा स्पष्ट होगा। –

2

मैं जानता हूँ कि मैं अपने कॉलबैक फ़ंक्शन के अंदर ताले को लागू कर सकते हैं, लेकिन मुझे लगता है कि और अधिक सुरुचिपूर्ण अगर यह टाइमर स्तर में हो जाएगा हो जाएगा

तो ताला आवश्यक है तो कैसे एक टाइमर की व्यवस्था कर सकता है कि ? आप एक जादुई फ्रीबी की तलाश में हैं।

पुन Edit1:

आपके विकल्प System.Timers.Timer और System.Threading.Timer कर रहे हैं, दोनों फिर से प्रवेश द्वार के खिलाफ सावधानियों की जरूरत है। this page देखें और टाइमर इवेंट रीन्ट्रेंस अनुभाग से निपटने के लिए देखें।

+0

मेरा संपादन 1 देखें, क्या यह आपको समझ में आता है? – Delashmate

+0

@ हांक मैंने आपके द्वारा वर्णित अनुभाग को पढ़ा है, मुझे आपको जवाब पसंद आया, लेकिन चिबैसिटी ने मेरे प्रश्न के लिए मेरा अधिक उपयुक्त उत्तर दिया, क्योंकि मैं इसे टाइमर सेटिंग के अंदर प्रबंधित करना चाहता हूं .. और कॉलबैक funciton के अंदर तर्क दर्ज नहीं करना, धन्यवाद – Delashmate

-1

आपके साझा डेटा के बारे में टाइमर कैसे पता लगा सकता है?

टाइमर कॉलबैक कुछ थ्रेडपूल थ्रेड पर निष्पादित किया जाता है। तो आपके पास कम से कम 2 धागे होंगे:

  1. आपका मुख्य धागा जहां टाइमर बनाया और लॉन्च किया गया है;
  2. कॉलबैक लॉन्च करने के लिए थ्रेडपूल से थ्रेड।

और आपके साझा डेटा के साथ सही काम प्रदान करना आपकी ज़िम्मेदारी है।

पुन: संपादन: chibacity ने एक आदर्श उदाहरण प्रदान किया।

+0

@downvoter: मेरे उत्तर में क्या गलत है? –

3

System.Timers.Timer के लिए टिम लॉयड के समाधान के पूरक है, यहाँ ऐसे मामलों में जहां आप के बजाय System.Threading.Timer उपयोग करना चाहते हैं के लिए reentrancy को रोकने के लिए एक समाधान है।

TimeSpan DISABLED_TIME_SPAN = TimeSpan.FromMilliseconds(-1); 

TimeSpan interval = TimeSpan.FromSeconds(1); 
Timer timer = null; // assign null so we can access it inside the lambda 

timer = new Timer(callback: state => 
{ 
    doSomeWork(); 
    try 
    { 
    timer.Change(interval, DISABLED_TIME_SPAN); 
    } 
    catch (ObjectDisposedException timerHasBeenDisposed) 
    { 
    } 
}, state: null, dueTime: interval, period: DISABLED_TIME_SPAN); 

मेरा मानना ​​है कि आप नहीं चाहते interval कॉलबैक के अंदर ही ऐक्सेस किया जाना है, लेकिन यह है कि, ठीक करने के लिए आसान हो सकता है अगर आप चाहते हैं के लिए है: एक NonReentrantTimer वर्ग कि बीसीएल के Timer वर्ग लपेटता में ऊपर रखो। इसके बाद आप पैरामीटर के रूप में doSomeWork कॉलबैक पास करेंगे। इस तरह के एक वर्ग का एक उदाहरण:

public class NonReentrantTimer : IDisposable 
{ 
    private readonly TimerCallback _callback; 
    private readonly TimeSpan _period; 
    private readonly Timer _timer; 

    public NonReentrantTimer(TimerCallback callback, object state, TimeSpan dueTime, TimeSpan period) 
    { 
     _callback = callback; 
     _period = period; 
     _timer = new Timer(Callback, state, dueTime, DISABLED_TIME_SPAN); 
    } 

    private void Callback(object state) 
    { 
     _callback(state); 
     try 
     { 
      _timer.Change(_period, DISABLED_TIME_SPAN); 
     } 
     catch (ObjectDisposedException timerHasBeenDisposed) 
     { 
     } 
    } 


    public void Dispose() 
    { 
     _timer.Dispose(); 
    } 
} 
0
/// <summary> 
/// The C#6 version 
/// </summary> 
public class TimerNicer : IDisposable { 
    private Action OnElapsed { get; } 

    [NotNull] 
    private System.Timers.Timer Timer { get; } = new System.Timers.Timer { AutoReset = false, Interval = 1 }; 

    public TimerNicer(Action onElapsed) { 

     this.OnElapsed = onElapsed ?? (() => { 
     }); 

     this.Timer.Elapsed += (sender, args) => { 

      this.Timer.Stop(); // Why not stop the timer here with this? 

      try { 
       this.OnElapsed(); // do stuff here 
      } 
      catch (Exception exception) { 
       Console.WriteLine(exception); 
      } 
      finally { 
       this.Timer.Start(); 
      } 
     }; 

     this.Timer.Start(); 
    } 

    public void Dispose() => this.Timer.Dispose(); 
}