# Synchronizacja Wątków

Skoro osiągnąłeś już wystarczająco zaawansowane umiejętności kodowania na żywo (live coding) wraz z wykorzystaniem jednocześnie funkcji i wątków, na pewno zauważyłeś już, że bardzo łatwo jest popełnić błąd w jednym z wątków co powoduje, że zostaje on zabity. To nie jest wielka rzecz, ponieważ możesz bardzo łatwo zrestartować wątek poprzez ponowne naciśnięcie przycisku Run. Jednakże, kiedy zrestartujesz wątek to wypadnie on teraz z rytmu oryginalnych wątków.

## Odziedziczony Czas

Jak już mówiliśmy wcześniej, nowe wątki tworzone z wykorzystaniem polecenia `in_thread` dziedziczą wszystkie ustawienia z wątku rodzica. W skład tych ustawień wchodzi też aktualny czas. Oznacza to, że wątki pozostają zawsze w korelacji czasowej kiedy zostaną uruchomione jednocześnie.

Jendakże, kiedy uruchomisz samodzielny wątek, rozpoczyna się on ze swoim własnym czasem i jest mało prawdopodobne, że będzie on w synchronizacji z jakimkolwiek innym uruchomionym aktualnie wątkiem.

## Cue (Wskazówka) i Sync (Synchronizacja)

Sonic Pi udostępnia rozwiązanie dla tego problemu za pomocą funkcji `cue` (wskazówka) i `sync` (synchronizacja).

`cue` pozwala nam na wysłanie wiadomości o pulsie to wszystkich innych aktualnie uruchomionych wątków. Domyślnie inne wątki nie są tym zainteresowane i ignorują tę wiadomość o pulsie. Jendakże, możesz bardzo łatwo wywołać takie zainteresowanie za pomocą funkcji `sync`.

Ważną rzeczą, której należy być świadomym jest to, że funkcja `sync` jest podobna do funkcji `sleep` w taki sposób, że powstrzymuje ona aktualny wątek od robienia czegokolwiek przez pewien okres czasu. Jednakże, w przypadku funkcji `sleep` musisz zdefiniować jak długo chcesz poczekać, natomiast w przypadku funkcji `sync` nie wiesz jak długo będziesz chicał poczekać, ponieważ funkcja `sync` czeka na następny punkt `cue` z innego wątku, co może nastąpić szybciej lub później.

Spróbujmy przyjrzeć się temu trochę bardziej dokładnie:

    in_thread do
      loop do
        cue :tick
        sleep 1
      end
    end

    in_thread do
      loop do
        sync :tick
        sample :drum_heavy_kick
      end
    end

Mamy tutaj dwa wątki - jeden zachowuje się jak metronom, nie gra żadnych dźwięków tylko wysyła komunikat `:tik` (cyk) przy każdym uderzeniu. Drugi wątek synchronizuje się natomiast przy otrzymaniu każdej kolejnej wiadomości `:tick` i kiedy otrzymuje kolejną odziedzicza czas uruchomienia `cue` i rozpoczyna swoje działanie.

Jako wynik słyszymy sampel `:drum_heavy_kick` dokładnie w tym samym momencie gdy inny wątek wysyła komunikat `:tick`, nawet jeśli obydwa wątki nie zostały uruchomione w tym samym czasie.

    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

Te niegrzeczne polecenie `sleep` normalnie stworzyłoby drugi wątek, który byłby zupełnie niezsynchronizowany z pierwszym. Jednakże, dzięki użyciu poleceń `cue` i `sync` automatycznie synchronizujemy wątki blokując jednocześnie jakiekolwiek nieprzewidziane rozjazdy w czasie.

## Nazwy dla komunikatów Cue

Dla nazw twoich komunikatów `cue` możesz używać dowolnych nazw - może to być nie tylko `:tick`. Musisz się tylko upewnić, że inne wątki `sync`hronizują się z właściwą nazwą - w przeciwnym wypadku będą czekać w nieskończoność (albo do momentu, w którym naciśniesz przycisk Stop).

Spróbujmy pobawić się z kilkoma komunikatami `cue` o różnych nazwach:

    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

Mamy tutaj główną pętlę `cue`, która co iterację wysyła komunikat z losową wybraną nazwą punktu cue do synchronizacji - `:foo`, `:bar` lub `:baz`. Następnie mamy trzy wątki z pętlami, które synchronizują się na każdym z tych komunikatów niezależnie i odtwarzają różne sample. Wynikiem tego jest to, że słyszymy dźwięk co każde 0.5 uderzenia jako, że każdy z synchronizowanych (`sync`) wątków jest wybierany losowo z wątku `cue` po czym odtwarza swojego sampla.

Oczywiście to wszystko zadziała analogicznie nawet jeśli poukładasz wątki w odwrotnej kolejności jako, że wątek `sync` będzie po prostu czekał na kolejną wartość wysłaną przez wątek `cue`.