Come assicurarsi che il metodo finisca di funzionare prima di essere eseguito di nuovo

2

Sono nuovo e sto cercando di capire qualcosa. Ho un semplice programma che esegue un metodo sia quando un evento accade o quando il mio timer ticchetta. Diciamo solo che il metodo impiega 5 secondi per essere completato. Durante questi 5 secondi potrebbe verificarsi un evento. Che cosa utilizzerei / fare per assicurarmi che il mio metodo non venga chiamato mentre è già in esecuzione.

O è qualcosa di cui non mi dovrei preoccupare in un programma semplice, in quanto non funzionerebbe fino a quando il metodo non viene eseguito comunque?

Un po 'di background ed esempio. Sto usando System.Windows.Forms.Timer, non sto usando alcun thread o altro, e ho solo una semplice applicazione Windows con un timer, un metodo per fare cose e due gestori di eventi.

Program{
  public Program(){
    DoSomething();
    Event.EventHappened += HandleEvent;
  }
  void DoSomething(){
    MyTimerVariable.Stop();
    InitMyTimer();
    //Just do something check network, access db write line, something
    //that in this example takes 5 secs for example purposes
    MyTimerVariable.Start();
  }
  void HandleEvent(){
    DoSomething();
  }
  void InitMyTimer(){
    // Create Timer, and add Timer tick event
  }
  void TimerTickedEvent(){
    DoSomething();
  }
}

Ho lasciato alcune cose fuori da quel programma, ma stavo solo cercando di mostrare quanto sia semplice. Stavo solo pensando di renderlo più efficiente in modo che nel bel mezzo di "DoSomething ()" venga attivato un evento, non vorrei che due metodi "DoSomething ()" funzionassero.

    
posta RWhiten 03.02.2014 - 04:50
fonte

3 risposte

5

Poiché utilizza System.Windows.Forms.Timer anziché System.Threading.Timer, l'evento verrà eseguito sul thread dell'interfaccia utente e pertanto non verrà eseguito fuori sequenza.

Se si stesse utilizzando la filettatura, semplicemente creando un private object lockObject = new object(); e bloccandolo nel metodo DoSomething() , si assicurerà analogamente che il corpo di DoSomething non venga eseguito fino al termine.

    
risposta data 03.02.2014 - 05:03
fonte
2

Se il vero intento è quello di assicurarti di non avere più metodi di lavoro attivi allo stesso tempo, il modo più semplice sarebbe qualcosa del tipo:

bool isBusy = false;
void MyWorkerMethod()
{
  if(isBusy == true)
  {
    return;
  }

  try
  {
    isBusy = true;
    // do stuff
  }
  finally
  {
    isBusy = false;
  }
}

In questo modo ogni volta che il timer scandisce, esegue comunque il tuo metodo, ma il tuo metodo uscirà immediatamente se è nel mezzo di lavorare con un minimo di confusione. Se utilizzi il blocco, avrai contesa sui thread mentre le cose si accumulano in attesa che il blocco si liberi, cosa che presumo non sia ciò che desideri.

Se sei un super paranoico, puoi anche esaminare le API interbloccate. * per assicurarti oltre ogni dubbio che il tuo lavoratore non venga mai eseguito più di una volta, ma potrebbe essere eccessivo.

    
risposta data 07.02.2014 - 00:22
fonte
2

Devo concordare con @theficus per lo stile del codice.

Tuttavia, non con l'implementazione in dettaglio.

Ho avuto molti casi in cui più di un thread ha inserito un blocco di codice usando solo il suo tipo di implementazione booleana del controllo. Sollevare ogni tipo di scempio e confusione, dato che l'impossibile assunto è realmente accaduto. Qualsiasi tipo di algoritmo di thread lock che funzioni solo la maggior parte del tempo ma non ogni volta è IMHO inutile.

L'API interbloccata. * per questo caso d'uso è tanto semplice quanto l'implementazione boolean-check e rende assolutamente sicuro che solo un thread entri nel blocco di codice e tutti gli altri continuino.

private int isBusy = 0;

private void MyWorkerMethod()
{
  if(System.Threading.Interlocked.CompareExchange(ref this.isBusy, 1, 0) == 1)
  {
    return;
  }

  try
  {
    // do stuff
  }
  finally
  {
    this.isBusy = 0;
  }
}
    
risposta data 28.09.2018 - 16:36
fonte

Leggi altre domande sui tag