Domanda

Ho un timer che non deve elaborare contemporaneamente il gestore eventi trascorso. Ma l'elaborazione di un evento trascorso può interferire con altri. Ho implementato la soluzione di seguito, ma qualcosa non va; sembra che dovrei usare il timer in modo diverso o usare un altro oggetto nello spazio di threading. Il timer sembrava adattarsi meglio perché devo controllare periodicamente uno stato, ma a volte il controllo richiederà più tempo del mio intervallo. È questo il modo migliore per affrontarlo?

// member variable
private static readonly object timerLock = new object();
private bool found = false;


// elsewhere
timer.Interval = TimeSpan.FromSeconds(5).TotalMilliseconds;
timer.Elapsed = Timer_OnElapsed;
timer.Start();


public void Timer_OnElapsed(object sender, ElapsedEventArgs e)
{
  lock(timerLock)
  {
    if (!found)
    {
      found = LookForItWhichMightTakeALongTime();
    }
  }
}
È stato utile?

Soluzione

È possibile impostare AutoReset su false, quindi reimpostare esplicitamente il timer dopo aver finito di gestirlo. Naturalmente, il modo in cui lo gestisci dipende davvero da come ti aspetti che funzioni il timer. Farlo in questo modo consentirebbe al timer di allontanarsi dall'intervallo specificato effettivo (così come interrompere e riavviare). Il tuo meccanismo consentirebbe l'attivazione e la gestione di ogni intervallo, ma potrebbe comportare un arretrato di eventi non gestiti che vengono gestiti ora in prossimità della scadenza del timer che causa l'invocazione del gestore.

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();
}

Altri suggerimenti

Di solito interrompo il timer durante l'elaborazione, inserisco un blocco try / finally e al termine riprendo il timer.

Se LookForItWhichMightTakeALongTime () impiegherà molto tempo, suggerirei di non utilizzare un System.Windows.Forms.Timer perché in questo modo bloccherai l'interfaccia utente thread e l'utente potrebbe uccidere l'applicazione pensando che sia stata bloccata.

Quello che potresti usare è un BackgroundWorker (insieme a un Timer se lo desideri).

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;
  }
}

E puoi chiamare RunWorkerAsync () da qualsiasi luogo tu voglia, anche da un Timer se vuoi. E assicurati solo di verificare se BackgroundWorker è già in esecuzione da quando hai chiamato RunWorkerAsync () quando è in esecuzione genererà un'eccezione.

private void timer_Tick(object sender, EventArgs e)
{
  if (!backgroundWorker.IsBusy)
    backgroundWorker.RunWorkerAsync();
}
timer.enabled = false

o

timer.stop();

e

timer.enabled = true

o

timer.start();

Uso System.Threading.Timer in questo modo

 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));
        }



    }
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top