# Sincronizzazione dei thread

Raggiungendo un livello avanzato di live coding e usando molte funzioni e thread simultaneamente, ti sarai accordo che è semplice fare un errore che ferma un thread. Non è un problema perché puoi sempre farlo ripartire premendo Run ma, quando si riavvierà, sarà fuori tempo rispetto al thread originale.

## Ereditare il tempo

Come abbiamo discusso in precedenza, i nuovi thread creati con `in_thread` ereditano le impostazioni dal thread principale. Questo include, ovviamente, anche il tempo. Questo significa che i thread sono sempre a tempo quando partono in simultanea.

Tuttavia, quando fai partire un thread da solo, questo partirà con il suo tempo ed è davvero improbabile che sia sincronizzato con gli altri thread.

## Segnale (cue) e sincronizzazione

Sonic Pi offre una soluzione a questo problema con le funzioni `cue` e `sync`.

La funzione `cue`ci permette di inviare il messaggio del cuore pulsante a tutti gli altri thread. Di default, gli altri thread non sono interessati a ricevere questo messaggio e lo ignorano. È possibile, però, attivare l’interesse al segnale utilizzando la funzione `sync`.

La cosa importante da sapere è che `sync` funziona in modo simile a `sleep` nel senso che ferma il thread corrente per un certo periodo di tempo. La differenza è che con `sleep` specifichiamo quanto tempo aspettare mentre con `sync` non è possibile sapere quando aspetterà dal momento che `sync` aspetta il segnale `cue` da un altro thread che potrebbe essere vicino oppure lontano nel tempo.

Proviamo ad andare nel dettaglio:

    in_thread do
      loop do
        cue :tick
        sleep 1
      end
    end
    in_thread do
      loop do
        sync :tick
        sample :drum_heavy_kick
      end
    end

Qui abbiamo due thread, uno che si comporta come un metronomo e non riproduce alcun suono ma invia il segnale `:tick` a ogni battito. Il secondo thread è sincronizzato al messaggio `tick` e quando ne riceve uno, eredita il tempo del thread `cue`e continua a funzionare.

Di conseguenza, sentiremo il campione `:drum_heavy_kick` esattamente nel momento in cui l’altro thread invia il messaggio `:tick`, anche se i due thread non vengono avviati in contemporanea:

    in_thread do
      loop do
        cue :tick
        sleep 1
      end
    end
    sleep(0.3)
    in_thread do
      loop do
        sync :tick
        sample :drum_heavy_kick
      end
    end

Quella chiamata a `sleep` normalmente manderebbe il secondo thread fuori fase rispetto al primo, ma, dal momento che usiamo `cue` e `sync`, sincronizziamo automaticamente i thread bypassando ogni possibile deviazione di tempo.

## Nominare i segnali di cue

Sei libero di usare tutti i nomi che vuoi per i messaggi `cue`, non solo `:tick`. Devi solo assicurarti che tutti i thread siano sincronizzati sullo stesso nome, altrimenti aspetteranno all’infinito (o, fino alla pressione del pulsante di Stop).

Facciamo qualche prova con diversi nomi per `cue`:

    in_thread do
      loop do
        cue [:foo, :bar, :baz].choose
        sleep 0.5
      end
    end
    in_thread do
      loop do
        sync :foo
        sample :elec_beep
      end
    end
    in_thread do
      loop do
        sync :bar
        sample :elec_flip
      end
    end
    in_thread do
      loop do
        sync :baz
        sample :elec_blup
      end
    end

Qui abbiamo un loop principale `cue` che in modo casuale invia segnali chiamati `:foo`, `:bar` o `:baz`. Abbiamo poi tre thread di loop con suoni differenti, ciascuno dei quali si sincronizza con quei segnali in modo indipendente. L’effetto rete fa si che sentiamo un suono ogni 0.5 battiti dal momento che ciascuno dei thread `sync` è sincronizzato in modo casuale con i thread `cue` che riproducono il campione.

Questo ovviamente funziona se ordini i thread al contrario dal momento che i thread `sync` aspetteranno di ricevere il `cue` successivo.