2009-05-02 5 views
12

Ich habe einen Timer, der seinen Handler für verstrichene Ereignisse nicht gleichzeitig verarbeiten muss. Aber die Verarbeitung eines verstrichenen Ereignisses kann mit anderen stören. Ich habe die folgende Lösung implementiert, aber etwas stimmt nicht. Es scheint entweder, ich sollte den Timer anders verwenden oder ein anderes Objekt innerhalb des Threading-Bereichs verwenden. Der Timer schien am besten zu passen, da ich regelmäßig nach einem Status suchen muss, aber manchmal dauert die Überprüfung länger als mein Intervall. Ist das der beste Weg, um das zu erreichen?Wie kann ein Timer während der Verarbeitung des verstrichenen Ereignisses blockiert werden?

+2

Dies sollte kein Community-Wiki gewesen sein. – Samuel

+0

@ Samuel - jede Frage kann Gemeinschaft Wiki sein, wenn das Plakat wünscht. Die FAQ gibt nur an, dass einige Fragen von Anfang an Community-Wiki sein sollten, schränkt jedoch nicht die Anwendung von CW auf eine Frage ein. – tvanfosson

+1

@tvanfosson: Ich habe ihn wissen lassen, dass Fragen wie diese nicht Community-Wiki sein sollten. – Samuel

Antwort

13

Sie könnten AutoReset auf false setzen und dann den Timer explizit zurücksetzen, nachdem Sie damit fertig sind. Wie Sie damit umgehen, hängt natürlich davon ab, wie Sie den Timer erwarten. Auf diese Weise würde Ihr Timer vom aktuell festgelegten Intervall abweichen (ebenso wie das Stoppen und Neustarten). Ihr Mechanismus würde ermöglichen, dass jedes Intervall ausgelöst und behandelt wird, aber es kann zu einem Rückstand von nicht behandelten Ereignissen kommen, die jetzt behandelt werden, wo der Ablauf des Timers, der den Aufruf des Handlers verursacht hat, kurz bevorsteht.

timer.Interval = TimeSpan.FromSeconds(5).TotalMilliseconds; 
timer.Elapsed += Timer_OnElapsed; 
timer.AutoReset = false; 
timer.Start(); 


public void Timer_OnElapsed(object sender, ElapsedEventArgs e) 
{ 
    if (!found) 
    { 
     found = LookForItWhichMightTakeALongTime(); 
    } 
    timer.Start(); 
} 
+0

AutoReset und Elapsed sind für System.Threading.Timer, was nicht sicher für die UI-Arbeit ist. – Samuel

+0

@Samuel - Elapsed ist das Ereignis, das vom OP verwendet wird. Vermutlich ist das keine WinForms App. – tvanfosson

8

Normalerweise stoppe ich den Timer während der Verarbeitung, gebe einen try/finally Block ein und setze den Timer wieder, wenn du fertig bist.

0
timer.enabled = false 

oder

timer.stop(); 

und

timer.enabled = true 

oder

timer.start(); 
-1

Ich benutze die System.Threading.Timer wie so

class Class1 
    { 
     static Timer timer = new Timer(DoSomething,null,TimeSpan.FromMinutes(1),TimeSpan.FromMinutes(1)); 

     private static void DoSomething(object state) 
     { 
      timer = null; // stop timer 

      // do some long stuff here 

      timer = new Timer(DoSomething, null, TimeSpan.FromMinutes(1), TimeSpan.FromMinutes(1)); 
     } 



    } 
+1

Sie sollten Timer-Instanzen immer abstellen, wenn Sie fertig sind. –

+0

Der Timer wird weiterhin die Callback-Methode auslösen, solange der Garbage Collector nicht aufgeräumt hat.Dies kann zu unerwarteten, nicht deterministischen Effekten führen. –

1

Wenn LookForItWhichMightTakeALongTime() eine lange Zeit in Anspruch nehmen wird, würde ich vorschlagen, keine System.Windows.Forms.Timer verwenden, weil damit Ihren UI-Thread und der Benutzer sperren kann töten Ihre Anwendung zu denken, dass es gefroren ist.

Was Sie verwenden könnten, ist ein BackgroundWorker (zusammen mit einem Timer wenn gewünscht).

public class MyForm : Form 
{ 
    private BackgroundWorker backgroundWorker = new BackgroundWorker(); 

    public MyForm() 
    { 
    InitializeComponents(); 
    backgroundWorker.DoWork += backgroundWorker_DoWork; 
    backgroundWorker.RunWorkerCompleted += 
           backgroundWorker_RunWorkerCompleted; 
    backgroundWorker.RunWorkerAsync(); 
    } 

    private void backgroundWorker_DoWork(object sender, DoWorkEventArgs e) 
    { 
    e.Result = LookForItWhichMightTakeALongTime(); 
    } 

    private void backgroundWorker_RunWorkerCompleted(object sender, 
              RunWorkerCompletedEventArgs e) 
    { 
    found = e.Result as MyClass; 
    } 
} 

Und Sie können Sie RunWorkerAsync() von überall anrufen wollen, auch von einem Timer wenn Sie möchten. Und stellen Sie sicher, zu überprüfen, ob die BackgroundWorker bereits seit dem Aufruf RunWorkerAsync() ausgeführt wird, wenn es eine Ausnahme auslöst.

private void timer_Tick(object sender, EventArgs e) 
{ 
    if (!backgroundWorker.IsBusy) 
    backgroundWorker.RunWorkerAsync(); 
} 
Verwandte Themen