# 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 Uruchom. 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.

Jednakż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, który jest aktualnie uruchomiony.

## 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 do wszystkich innych aktualnie uruchomionych wątków. Domyślnie inne wątki nie są tym zainteresowane i ignorują tę wiadomość, jednakże możesz bardzo łatwo wywołać takie zaintrygowanie za pomocą funkcji `sync`.

Ważną rzeczą, której należy być świadomym, jest to, że funkcja `sync` wygląda podobnie 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 funkcji `sync` nie wiesz, jak długo będziesz chciał poczekać, ponieważ ta funkcja 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 z nich 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 słów - 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`.