Un'alternativa ai thread utilizza un meccanismo di evento (interrupt) accoppiato con un "ciclo principale" che esegue il pulsante e il codice di spegnimento e un intervallo di timer come "scheduler" per capire quale pezzo di codice da eseguire successivamente. In questo caso ci sono tre tipi di eventi che devi affrontare:
- pulsante1 o pulsante2 premuto
- segnale di spegnimento
- segnale del timer, in un intervallo di dire ogni 500 ms
L'idea è la seguente:
- ogni volta che viene premuto un pulsante, ricorda quale pulsante era
- ogni volta che scatta il timer, controlla quale parte del codice evento (pulsante) deve essere eseguito successivamente
- esegui il codice evento come parte del ciclo principale
- dividere il codice evento in più parti, dopo ogni pezzo controllare se si è verificato il segnale di spegnimento. Se è così, esci.
Nel gestore del timer, controlla quale parte del codice evento deve essere eseguita successivamente, in base a quale pulsante è stato visualizzato nel passaggio 1. Questo è lo "scheduler". In caso di segnale di spegnimento, ricordarsi di non eseguire alcun altro codice pulsante e, nel ciclo principale, eseguire invece il codice di spegnimento.
Il ciclo principale fa esattamente come suggerisce il nome:
interrupted = false; // assigned true on alternative button pressed
stopped = false; // assigned true at the end of power down
while(!stopped) {
while(!interrupted) {
run the code (piece of event code) determined by the scheduler
}
}
EDIT: spiega l'esempio in modo più dettagliato:
Wait, è proprio uguale all'esempio OP, ma più complicato!?
No. Qui la gestione, la programmazione e l'esecuzione degli eventi sono eliminati e non inquinano il "codice dei pulsanti". Piuttosto, il codice del pulsante viene mantenuto semplice e non "conosce" alcuna partizione, né è necessario prevedere una logica di "cancellazione". Si noti che la suddivisione del codice evento significa che ogni pezzo è essenzialmente un metodo semplice e separato la cui esecuzione viene attivata dal ciclo principale. Non ci sono "se-ladder" come nell'esempio di OP. Ciò mantiene la logica reale leggibile e mantenibile.
Cosa succede se il codice evento deve essere eseguito una sola volta?
Lo scheduler può anche essere esteso per consentire al codice evento, o ad alcune sue parti, di essere eseguito una sola volta. Per questo introdurre una struttura dati che tiene traccia di quale pezzo è stato eseguito. Ogni volta che viene eseguito lo scheduler, aggiorna la struttura dei dati e, in base alle condizioni impostate per ogni parte di codice, decide se deve essere pianificato o eseguito.
Perché non eseguire il codice del pulsante direttamente in ogni gestore di eventi?
È anche possibile eseguire il codice del pulsante direttamente nel passaggio 1, ma ciò renderebbe l'interfaccia utente lenta, poiché non risponderebbe fino a quando il codice non sarà terminato. Questo è il motivo per cui il gestore del timer ha bisogno di implementare un programmatore. Determina quale codice eseguire. Il codice effettivo può essere eseguito solo sul loop principale.
Perché non eseguire il codice del pulsante all'interno del gestore del timer?
È anche possibile eseguire il codice dei pulsanti direttamente all'interno del gestore del timer. Lo svantaggio è che dovresti assicurarti che il codice non superi la durata dell'intervallo del timer per evitare interruzioni eccessive o peggio.
Non è troppo complesso ?
Questo progetto può sembrare eccessivamente complicato all'inizio, ma garantisce che il sistema continui a funzionare senza intoppi separando UI, pianificazione e esecuzione effettiva del codice. L'alternativa, ovviamente, è usare i thread, ma poi il punto centrale di questa risposta è mostrare una soluzione withouth threads.
Ci sono miglioramenti, ad es. per i vincoli in tempo reale?
In sostanza, tutto questo si riduce a un problema di pianificazione. Vedi Scheduling Algorithms (Wikipedia) per approcci più sofisticati, ad es. per gestire i requisiti in tempo reale.