Puoi acquisire le competenze di programmazione necessarie facendo prima un progetto più semplice: simula un sistema di massa primaverile secondo la fisica. Una volta raggiunto questo traguardo, sarà più facile per te concettualizzare un sistema più grande.
Il tuo programma è un ciclo. Ad ogni passo temporale ("tick of time"), ad esempio t
, il tuo programma deve calcolare i parametri (posizione, velocità, accelerazione, decisione dell'autista) di ogni auto per il passo successivo, ad esempio t + 1
.
- Avrai una serie di macchine, diciamo
carCurrentStates[carNumber]
.
- Potrebbe essere necessario creare un array duplicato,
carNextStates[carNumber]
.
- Ad ogni passaggio temporale, utilizza le informazioni da
carCurrentStates[carNumber]
per calcolare le nuove informazioni per carNextStates[carNumber]
. Quando tutti i calcoli per la fase temporale sono terminati, copia le informazioni da carNextStates[carNumber]
a carCurrentStates[carNumber]
.
- L'array duplicato
carNextStates[carNumber]
può essere riutilizzato (sovrascritto) nel passaggio successivo.
Dovrai sincronizzare questi calcoli.
Sia che tu usi i thread o meno, dovrai usare alcuni tipi di tecniche di sincronizzazione. Le tecniche di sincronizzazione per i thread sono anche conosciute come barriere.
Gli scheduler dei thread non causano magicamente l'esecuzione dei thread in modo sincronizzato. Non danno magicamente la stessa quota di tempo a ciascuno dei tuoi thread. Se non si utilizzano tecniche di sincronizzazione, alcuni thread avranno tempi di esecuzione maggiori rispetto ad altri; perderanno la sincronizzazione.
Se più thread devono aggiornare (scrivere su) una determinata variabile di programma, che deve essere serializzata. La serializzazione indica che un thread può completare una sequenza di "lettura-modifica-scrittura" prima che un altro thread possa iniziare la propria sequenza di "lettura-modifica-scrittura". Se l'accesso alle variabili del programma non è serializzato, il risultato scritto di ciascun thread comprimerà il risultato precedente, o che un thread potrebbe eseguire calcoli basati su un risultato vecchio che è stato successivamente danneggiato.
Una volta che sai come implementare i calcoli in modo sincronizzato e aggiornare correttamente gli stati del programma, potresti scoprire che puoi implementare il progetto con o senza thread.
Per simulare il comportamento del conducente, ogni driver accelererà o decelererà secondo:
- Qual è la mia velocità? (Bassa / media / alta)
- Qual è la velocità delle corsie adiacenti?
- Quanto è distante l'auto di fronte a me?
- Lo spazio tra me e la macchina di fronte: crescente (accelerando più veloce di me), stesso (stessa velocità / stessa accelerazione) o decrescente?
- Sto progettando di cambiare corsia? Se è così, ho bisogno di abbinare la velocità di quell'altra corsia.
- Ho qualche altra ragione per rallentare? Se ho intenzione di uscire da un'autostrada, o se c'è un semaforo, o se c'è una curva strong, allora ho bisogno di rallentare.
- Devo fermarmi completamente a un certo punto? Se sto raggiungendo la mia destinazione, o se il semaforo è rosso, allora non mi è permesso di oltrepassarlo. Devo frenare il più strong possibile, se necessario.