Progettazione di funzioni software che sono sia pausabili che riavviabili

3

Considera la seguente situazione:

Un dispositivo hardware, due applicazioni (1 applicazione C #, 1 firmware). L'applicazione C # invia frame al firmware e il firmware esegue script.

  • C # - > trasmetti frame [x]
  • FW - > ricevi frame [x]
  • FW - > esegui lo script relativo a frame [x]
  • FW - > prima della fine, viene attivato un evento FW costringendo le parti mobili a fermarsi (precauzione di sicurezza).

Requisito C # dopo che tali eventi sono stati sollevati:

  • Sondare FW per stato, se stato == fermato, inviare un curriculum fama.
  • Avvertenza: la logica C # deve quindi adattarsi per essere "riavviata".

Quindi questa è la situazione che ho; ma quello di cui cerco il parere è come dovrei progettare una classe in grado di gestire la sospensione e il riavvio delle attività un numero illimitato di volte.

Mentre posso scrivere metodi complessi che sono difficili da mantenere attraverso una catena di affermazioni logiche, sto lottando per trovare un progetto che sia riutilizzabile e pulito.

Tali scenari sono veri per ~ 50 compiti unici, quindi trovare una soluzione che posso applicare ogni volta farebbe risparmiare un sacco di mal di testa. Ogni volta che uno script viene riavviato o riavviato, un utente fisico può facilmente causare un arresto del trigger di sicurezza, pertanto una soluzione deve essere solida.

Anche se sono sicuro che la ricorsione sarebbe un primo buon passo, sono preoccupato che i limiti dello stack abbiano il potenziale per introdurre errori.

Chiarimento:

Nel mio tentativo di semplificare le cose, mi sembra di aver omesso troppo. Scuse.

Firmware: Software in esecuzione su un dispositivo fisico che controlla l'hardware. Non ho il controllo su questo code-base ed è stato progettato in modo indipendente pur consentendo la comunicazione USB.

Sincronizzazione: C'è poca o nessuna sincronizzazione tra l'applicazione C # e il firmware. Il mio codice C # invierà un frame di byte che corrisponde a un documento di specifiche per il firmware, e se il frame è valido, il firmware risponderà dicendo che ha ricevuto il frame e inizierà il lavoro. Dopodiché, non c'è sincronizzazione diretta. Un'attività descritta da un frame ha in genere due attributi: il tempo necessario per l'esecuzione (necessità di osservare manualmente) e uno stato di destinazione finale (completo di identificatori di stato). Attualmente eseguo il polling del firmware per lo stato finché non viene raggiunto lo stato target o fino al timeout.

La ricorsione: Ciò che intendevo era ( if not complete - > callSelfAgain() )

Pausa: l'utente ha fatto qualcosa al dispositivo, aspetta qui fino a quando non si risolve (può accadere in QUALSIASI momento durante il periodo in cui il firmware sta eseguendo i suoi lavori).

Riavvia: l'utente ha modificato lo stato, ora inizia il lavoro dall'inizio (o da dove ci eravamo interrotti [dipendente dall'attività]).

    
posta BlackBox 28.03.2014 - 23:11
fonte

1 risposta

3

Penso che la soluzione migliore sia progettare il sistema come macchina di stato . L'idea è che hai oggetti che simboleggiano ogni fase discreta del processo, inclusi tutti i dati di stato accumulati finora e, puntando alla sottoattività attualmente in esecuzione, puoi ricostruire l'esecuzione da quel punto.

Tuttavia, ho appena ricordato che esiste un meccanismo C # che funziona effettivamente in in questo modo preciso e soddisfa anche tutti i tuoi requisiti. Sebbene non siano stati creati per questo scopo, puoi implementare il design utilizzando iteratori .

Già supportano la sospensione dell'esecuzione in punti arbitrari e supportano anche il riavvio di un numero qualsiasi di elementi in caso di necessità. In realtà non devono restituire un valore, ma possono farlo, e questo è un bonus.

public class Unit {
    private Unit() {

    }
}
public class StateMachine {

    public IEnumerable<Unit> Run(int input) {

        int working = input + 1;
        yield return null; //stop execution
        //restarting... we still have all the working state data!
        working *= input;
        //more work...
        yield return null; //stop work
        //restart...
        if (IsError()) {
            throw new Exception();
        }
        if (IsOverPrematurely()) {
            yield break;
        }
    }
}

(Potrei essere frainteso indipendentemente dal fatto che la tua domanda richieda o meno un valore di ritorno, però.)

    
risposta data 29.03.2014 - 12:35
fonte