2010-06-06 40 views
10

मैं f() प्रत्येक t समय विधि का आह्वान करने का प्रयास कर रहा हूं, लेकिन अगर f() का पिछला आमंत्रण अभी तक समाप्त नहीं हुआ है, तो यह समाप्त होने तक प्रतीक्षा करें।गैर-पुनर्वित्तक सी # टाइमर

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

स्पष्ट करने के लिए, अगर t एक सेकंड है, और f() चलाता मनमाना अवधि मैं नीचे लिखा है, तो:

Step Operation Time taken 
1  wait   1s 
2  f()   0.6s 
3  wait   0.4s (because f already took 0.6 seconds) 
4  f()   10s 
5  wait   0s (we're late) 
6  f()   0.3s 
7  wait   0.7s (we can disregard the debt from step 4) 

सूचना इस टाइमर की प्रकृति है कि f() सुरक्षित होने की जरूरत नहीं है कि फिर से प्रवेश के संबंध में, और आकार 1 का धागा पूल यहां पर्याप्त है।

+0

लिंक मर चुका है। – astrowalker

+0

@astrowalker धन्यवाद! इसे अभी हटा दिया गया है, क्योंकि यह वास्तव में यहां जरूरी नहीं है। – Oak

उत्तर

8

आप केवल 'वैश्विक' स्तर var (या अधिक संभावना है, उसी वर्ग में सार्वजनिक संपत्ति f()) का उपयोग कर सकते हैं जो f() पहले से चल रहा है, तो यह सच हो जाता है।

तो अगर f()TimedEvent नाम के एक कक्षा में था, पहली बात यह है f() करना होगा सेट कर दिया जाता Running सच

उस स्थिति में आपके टाइमर आग हर दूसरे, तो समय घटना यदि वह पहले से
if (!timedEvent.Running) timedEvent.f()

चल नहीं है की शुरूआत

आपने टिप्पणी की कि f() टाइमर अंतराल से अधिक समय लेता है तो तुरंत दोहराना नहीं होगा। एक उचित बिंदु है। मैं शायद f() के अंदर तर्क शामिल करूँगा ताकि Running सच रहता है। तो यह इस तरह कुछ दिखाई देगा:

public void f(int t) // t is interval in seconds 
{ 
    this.running = true; 

    Stopwatch stopWatch = new Stopwatch(); 
    stopWatch.Start(); 

    do 
    { 
     stopwatch.Reset(); 

     // Do work here 

    } while (stopWatch.Elapsed.Seconds > t); // repeat if f() took longer than t 

    this.running = false; 
} 
+1

यदि आप ऐसा करते हैं, तो दौड़ की स्थिति से सावधान रहें। –

+0

सच है, लेकिन प्रश्नकर्ता ने कहा था कि इसे बहु-थ्रेड सुरक्षित होने की आवश्यकता नहीं है – PaulG

+0

बहुत ही सुरुचिपूर्ण, हालांकि इसका मतलब है कि दूसरा 'एफ' तुरंत 10.5 सेकंड 'एफ' का पालन नहीं करेगा, है ना? यह उनके बीच 0.5 सेकंड इंतजार करेगा ... – Oak

3

आप एक गैर-पुनरारंभ करने वाले टाइमर का उपयोग कर सकते हैं, फिर विधि समाप्त होने के बाद मैन्युअल रूप से टाइमर को पुनरारंभ करें।

ध्यान दें कि इसका परिणाम उस समय से होगा जो आप पूछ रहे हैं उससे कुछ अलग है।

आप lastTick + t - Now के अंतराल की स्थापना, और विधि तुरंत चालू है कि अगर <= 0 है द्वारा कि हल कर सकते थे (वहाँ हमेशा आमंत्रण के बीच t समय के अंतराल हो जाएगा)।

यदि आपको टाइमर को रोकने की आवश्यकता है तो दौड़ की स्थिति से सावधान रहें।

1

आपको बिल्कुल निर्धारित अंतराल पर कॉल करने के लिए टाइमर नहीं मिल सकता है। सभी टाइमर आपको पर अनुरोधित समय से से अधिक नहीं कहते हैं।

कुछ टाइमर दूसरों से बेहतर हैं (जैसे Windows.Forms.Timer System.Threading.Timer की तुलना में बहुत अनिश्चित और अविश्वसनीय है)

अपने टाइमर को रोकने के लिए बुलाया जा रहा है फिर से entrantly, एक दृष्टिकोण को रोकने के लिए है आपकी विधि चल रही है, जबकि टाइमर। (आपके द्वारा उपयोग किए जाने वाले टाइमर के प्रकार के आधार पर, आप या तो इसे रोकते हैं और फिर से शुरू करते हैं जब आपका हैंडलर निकलता है, या कुछ टाइमर के साथ आप कॉलबैक दोहराने के बजाए एक कॉलबैक का अनुरोध कर सकते हैं, इसलिए आपके हैंडलर के प्रत्येक निष्पादन को केवल अगली कॉल को एन्क्यूशन किया जाता है) ।

इन कॉलों के बीच अपेक्षाकृत समय को रखने के लिए आप समय रिकॉर्ड कर सकते हैं क्योंकि आपके हैंडलर ने अंतिम बार निष्पादित किया था और अगली घटना की आवश्यकता होने तक देरी की गणना करने के लिए इसका उपयोग किया था। जैसे यदि आप प्रति सेकंड एक बार कॉल करना चाहते हैं और आपका टाइमर 1.02 पर प्रोसेसिंग पूरा कर लेता है, तो आप इस तथ्य को समायोजित करने के लिए 0.98 की अवधि में अगली टाइमर कॉलबैक सेट कर सकते हैं कि आपने पहले से ही "इस्तेमाल किया" भाग लिया है आपकी प्रसंस्करण के दौरान दूसरा।

12

सिस्टम का उपयोग करें। थ्रेडिंग। टिमर। इसे टाइमआउट की अवधि के साथ शुरू करें। अनंत तो यह एक शॉट टाइमर की तरह कार्य करता है। जब f() पूर्ण हो जाता है, तो इसे फिर से रिचार्ज करने के लिए अपनी चेंज() विधि को कॉल करें।

+0

क्या आपका मतलब 'टाइमआउट। अनंत' पर निर्धारित अवधि है? – bavaza

0

एक सरल समाधान:

private class Worker : IDisposable 
{ 
    private readonly TimeSpan _interval; 
    private WorkerContext _workerContext; 

    private sealed class WorkerContext 
    { 
     private readonly ManualResetEvent _evExit; 
     private readonly Thread _thread; 
     private readonly TimeSpan _interval; 

     public WorkerContext(ParameterizedThreadStart threadProc, TimeSpan interval) 
     { 
      _evExit = new ManualResetEvent(false); 
      _thread = new Thread(threadProc); 
      _interval = interval; 
     } 

     public ManualResetEvent ExitEvent 
     { 
      get { return _evExit; } 
     } 

     public TimeSpan Interval 
     { 
      get { return _interval; } 
     } 

     public void Run() 
     { 
      _thread.Start(this); 
     } 

     public void Stop() 
     { 
      _evExit.Set(); 
     } 

     public void StopAndWait() 
     { 
      _evExit.Set(); 
      _thread.Join(); 
     } 
    } 

    ~Worker() 
    { 
     Stop(); 
    } 

    public Worker(TimeSpan interval) 
    { 
     _interval = interval; 
    } 

    public TimeSpan Interval 
    { 
     get { return _interval; } 
    } 

    private void DoWork() 
    { 
     /* do your work here */ 
    } 

    public void Start() 
    { 
     var context = new WorkerContext(WorkThreadProc, _interval); 
     if(Interlocked.CompareExchange<WorkerContext>(ref _workerContext, context, null) == null) 
     { 
      context.Run(); 
     } 
     else 
     { 
      context.ExitEvent.Close(); 
      throw new InvalidOperationException("Working alredy."); 
     } 
    } 

    public void Stop() 
    { 
     var context = Interlocked.Exchange<WorkerContext>(ref _workerContext, null); 
     if(context != null) 
     { 
      context.Stop(); 
     } 
    } 

    private void WorkThreadProc(object p) 
    { 
     var context = (WorkerContext)p; 
     // you can use whatever time-measurement mechanism you want 
     var sw = new System.Diagnostics.Stopwatch(); 
     int sleep = (int)context.Interval.TotalMilliseconds; 
     while(true) 
     { 
      if(context.ExitEvent.WaitOne(sleep)) break; 

      sw.Reset(); 
      sw.Start(); 

      DoWork(); 

      sw.Stop(); 

      var time = sw.Elapsed; 
      if(time < _interval) 
       sleep = (int)(_interval - time).TotalMilliseconds; 
      else 
       sleep = 0; 
     } 
     context.ExitEvent.Close(); 
    } 

    public void Dispose() 
    { 
     Stop(); 
     GC.SuppressFinalize(this); 
    } 
} 
0

कैसे विधि च() के प्रतिनिधियों का उपयोग कर, उन्हें एक ढेर करने के लिए कतार, और पॉपिंग ढेर के रूप में प्रत्येक प्रतिनिधि को पूरा करता है के बारे में? आपको अभी भी टाइमर की ज़रूरत है।

0

एक सरल धागा इसे प्राप्त करने का सबसे आसान तरीका है। आपका अभी भी यह सुनिश्चित नहीं होगा कि जब आप चाहें तो 'सटीक' कहा जाता है, लेकिन यह करीब होना चाहिए .... आप यह भी तय कर सकते हैं कि क्या आप को कॉल करना चाहते हैं या बैक अप लेने का प्रयास करना चाहते हैं ... थ्रेड बनाने के लिए यहां सरल सहायक रूटीन है।

public static Thread StartTimer(TimeSpan interval, Func<bool> operation) 
{ 
    Thread t = new Thread(new ThreadStart(
     delegate() 
     { 
      DateTime when = DateTime.Now; 
      TimeSpan wait = interval; 
      while (true) 
      { 
       Thread.Sleep(wait); 
       if (!operation()) 
        return; 
       DateTime dt = DateTime.Now; 
       when += interval; 
       while (when < dt) 
        when += interval; 
       wait = when - dt; 
      } 
     } 
    )); 
    t.IsBackground = true; 
    t.Start(); 
    return t; 
} 
0

लोग हैं, जो यहां भूमि "फिर से entrancy" के लिए खोज के लाभ के लिए: (मैं जानता हूँ कि यह मूल प्रश्न के लिए बहुत देर हो चुकी हो सकता है) एक खुले स्रोत संग्रहालय कि पहले से ही प्रदान करते हैं का उपयोग कर के खिलाफ नहीं है ऐसी कार्यक्षमता के लिए, मैंने Quartz.NET का उपयोग करके कार्यान्वयन के माध्यम से इसे सफलतापूर्वक हासिल किया है जब आप कोई नौकरी बनाते हैं और ट्रिगर संलग्न करते हैं, तो आप यह निर्दिष्ट कर सकते हैं कि पिछली ट्रिगर ने अपना काम निष्पादित करने के बाद क्या किया जाना चाहिए

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