Problema ricorrente: è necessario eseguire le istruzioni solo una volta all'interno del codice che viene eseguito più volte [chiuso]

0

Solitamente mi imbatto in questo problema (specialmente quando si tratta di determinati framework) in cui vorrei che una volta una parte di codice eseguisse una sola volta il metodo fornito, ad esempio (qualcosa come una funzione onComplete) che desidero inserire questa istruzione a volontà in realtà eseguire più volte.

Mi chiedo solo se qualcuno sa del modo migliore per risolvere questo problema, un mio amico programmatore mi ha detto di usare un flag (booleano) per verificare se questo codice è già stato eseguito, ma mi sento così non è una soluzione adatta e non vorrei introdurre variabili globali per il controllo di una condizione una sola volta.

Qualcuno ha mai incontrato un problema come questo, mi chiedo se ci siano buone pratiche da tenere a mente quando si tratta di codice come questo.

    
posta scrineym 15.08.2012 - 10:28
fonte

5 risposte

4

In C, usavo usare i puntatori di funzione per questo. La prima volta che è stata richiamata la funzione, è stata richiamata la funzione di inizializzazione. Alla fine della funzione di inizializzazione, ha cambiato il puntatore della funzione in modo che indicasse il codice che doveva essere chiamato il resto del tempo. Ci sono vari modi per farlo in altre lingue, con vari livelli di efficienza.

    
risposta data 15.08.2012 - 14:12
fonte
2

queste note potrebbero essere utili:

  1. Puoi creare una funzione idempotent , il che significa che non importa quante volte chiami quel metodo, ottieni sempre lo stesso risultato.
  2. Uso di un'istruzione if per controllare una condizione esterna ed eseguire il codice solo se tale condizione non viene soddisfatta. (Forse un'altra implementazione di idempotency)
  3. Come hai detto, inserisci questa dipendenza nel tuo metodo. Il tuo metodo dipende da uno stato esterno per dirlo quante volte è stato eseguito. Quindi se un altro gestore (contenitore) gestisce questo per il tuo metodo, le cose diventano più facili.
risposta data 15.08.2012 - 13:10
fonte
1

Il modo in cui è fatto in Grand Central Dispatch è di usare un tipo di semaforo chiamato "una volta token". Il tuo codice sarà simile a questo:

void do_something_once(once_token *token, void (*work)()) {
  if(atomic_read(token) == 0) {
    atomic_increment(token);
    work();
  }
}

void initialize() {/* the work */}

static once_token do_once = 0;
do_something_once(&do_once, initialize);

Dove i dettagli della lettura e dell'incremento atomico del token dipendono dalla piattaforma.

    
risposta data 15.08.2012 - 15:10
fonte
0

Un indicatore booleano che indica che il metodo è stato eseguito sarebbe la soluzione giusta.

Non sei sicuro del motivo per cui pensi che debba essere una variabile globale, ma può essere dichiarata al di fuori del ciclo prima che inizi a funzionare.

Se è necessario assicurarsi che il metodo venga eseguito solo una volta durante la durata dell'esecuzione del programma, ci sono diversi modi per farlo a seconda della lingua, ma si riducono sostanzialmente a un valore booleano globale ( anche se in alcune lingue che possono essere incapsulate).

Ad esempio in C #:

Si può avere il metodo live in una classe statica con un booleano statico privato - questo sarebbe visibile solo alla classe stessa ed è possibile impostarlo una volta che il metodo viene eseguito la prima volta. La prossima volta, poiché il flag è impostato, non esegui il corpo del metodo. La statistica è uno stato globale, ma come membro privato , la bandiera non è visibile ad altre classi.

    
risposta data 15.08.2012 - 10:36
fonte
0

In C # potresti usare una classe come questa:

public sealed class DoOnce
{
    private Action _action;

    public DoOnce(Action action)
    {
        _action = action;
    }

    public void Invoke()
    {
        var action = Interlocked.Exchange(ref _action, null);

        action?.Invoke();
    }
}

Quindi usarlo:

var doOnce = new DoOnce(() => Console.WriteLine("Just the one time"));
doOnce.Invoke(); // prints
doOnce.Invoke(); // doesn't print
doOnce.Invoke(); // doesn't print

Questo eseguirà l'azione solo una volta, ed è libero dalle condizioni di gara (è sicuro per i thread).

    
risposta data 20.02.2016 - 23:22
fonte

Leggi altre domande sui tag