Differences
This shows you the differences between two versions of the page.
| Both sides previous revisionPrevious revision | |||
| statnice:bakalar:b4b36pdv [2026/05/25 12:58] – jpelc | statnice:bakalar:b4b36pdv [2026/05/25 13:03] (current) – jpelc | ||
|---|---|---|---|
| Line 197: | Line 197: | ||
| * Pokud se to děje často, dochází k **velkému zpomalení**, | * Pokud se to děje často, dochází k **velkému zpomalení**, | ||
| * Řešení: | * Řešení: | ||
| - | * **Zarovnat proměnné** tak, aby každá byla na vlastní cache line (např. pomocí | + | * **Zarovnat proměnné** tak, aby každá byla na vlastní cache line (např. pomocí |
| * Přidat „padding“ mezi proměnné, které používají různá vlákna. | * Přidat „padding“ mezi proměnné, které používají různá vlákna. | ||
| Line 207: | Line 207: | ||
| ===== 3. Podpora paralelního programování v C a CPP ===== | ===== 3. Podpora paralelního programování v C a CPP ===== | ||
| - | Existuje více úrovní podpory – od nízkoúrovňových knihoven jako `pthreads` v C, až po elegantní moderní rozhraní ve stylu `std::thread`, `std:: | + | Existuje více úrovní podpory – od nízkoúrovňových knihoven jako '' |
| ==== POSIX vlákna (pthreads) ==== | ==== POSIX vlákna (pthreads) ==== | ||
| - | * `pthreads` (POSIX Threads) je **standardní rozhraní v jazyku C** pro práci s vlákny. | + | * '' |
| * Poskytuje funkce pro: | * Poskytuje funkce pro: | ||
| - | * **vytváření vláken**: | + | * **vytváření vláken**: |
| * **synchronizaci vláken**: | * **synchronizaci vláken**: | ||
| - | * **mutexy**: | + | * **mutexy**: |
| - | * **podmínkové proměnné**: | + | * **podmínkové proměnné**: |
| - | * **semafory**: | + | * **semafory**: |
| Je to výkonný, ale nízkoúrovňový nástroj – programátor musí vše spravovat ručně. Hodí se pro systémy, kde je důležitá kontrola nad výkonem a kompatibilita se standardem POSIX. | Je to výkonný, ale nízkoúrovňový nástroj – programátor musí vše spravovat ručně. Hodí se pro systémy, kde je důležitá kontrola nad výkonem a kompatibilita se standardem POSIX. | ||
| ==== std::thread (CPP11) ==== | ==== std::thread (CPP11) ==== | ||
| - | * Od CPP11 je k dispozici standardní knihovna pro vlákna – `std::thread`. | + | * Od CPP11 je k dispozici standardní knihovna pro vlákna – '' |
| * Umožňuje jednoduché vytvoření a správu vláken pomocí objektově orientovaného rozhraní. | * Umožňuje jednoduché vytvoření a správu vláken pomocí objektově orientovaného rozhraní. | ||
| * Vlákno spustíme předáním funkce (nebo lambdy) do konstruktoru. | * Vlákno spustíme předáním funkce (nebo lambdy) do konstruktoru. | ||
| - | * Synchronizace se řeší pomocí | + | * Synchronizace se řeší pomocí |
| - | Výhodou oproti | + | Výhodou oproti |
| ==== std:: | ==== std:: | ||
| - | * Od CPP20 přibyla nová třída | + | * Od CPP20 přibyla nová třída |
| - | * Při zničení objektu se vlákno **automaticky ukončí** (`join()` nebo `detach()`). | + | * Při zničení objektu se vlákno **automaticky ukončí** ('' |
| - | * Má vestavěnou podporu pro **zrušení vlákna** pomocí | + | * Má vestavěnou podporu pro **zrušení vlákna** pomocí |
| * Výborně se hodí pro práci s **RAII přístupem** a bezpečnější práci s vláknem. | * Výborně se hodí pro práci s **RAII přístupem** a bezpečnější práci s vláknem. | ||
| - | To znamená, že se snižuje riziko zapomenutého | + | To znamená, že se snižuje riziko zapomenutého |
| ==== Mutex a Lock Guard ==== | ==== Mutex a Lock Guard ==== | ||
| **Mutex** (*mutual exclusion*) je synchronizační nástroj, který **zajišťuje, | **Mutex** (*mutual exclusion*) je synchronizační nástroj, který **zajišťuje, | ||
| - | * V CPP se používá | + | * V CPP se používá |
| - | * `std:: | + | * '' |
| Ukázka (ruční zamykání/ | Ukázka (ruční zamykání/ | ||
| Line 267: | Line 267: | ||
| </ | </ | ||
| - | *Moderní CPP* doporučuje použít | + | *Moderní CPP* doporučuje použít |
| <code cpp> | <code cpp> | ||
| Line 295: | Line 295: | ||
| ==== Atomic ==== | ==== Atomic ==== | ||
| **Atomic** proměnné umožňují provádět operace, které jsou **nedělitelné (atomické)** – tím pádem **bezpečné vůči souběhu**, aniž by bylo potřeba používat mutex. | **Atomic** proměnné umožňují provádět operace, které jsou **nedělitelné (atomické)** – tím pádem **bezpečné vůči souběhu**, aniž by bylo potřeba používat mutex. | ||
| - | * V CPP se používá | + | * V CPP se používá |
| * V pozadí to využívá **atomické instrukce CPU** (pokud jsou dostupné), takže jsou **rychlejší než mutexy**. | * V pozadí to využívá **atomické instrukce CPU** (pokud jsou dostupné), takže jsou **rychlejší než mutexy**. | ||
| * Pokud HW atomické instrukce neumí, fallback je přes mutex. | * Pokud HW atomické instrukce neumí, fallback je přes mutex. | ||
| - | V praxi jsou tedy `std::atomic` velmi efektivní pro jednoduché sdílené proměnné – například čítače: | + | V praxi jsou tedy '' |
| <code cpp> | <code cpp> | ||
| Line 327: | Line 327: | ||
| </ | </ | ||
| - | * Jinými slovy – `std::atomic` je ideální, pokud chceš **rychlou synchronizaci bez složitých zámků**, ale nepotřebuješ složitou logiku jako čekání, notifikace, podmínky apod. | + | * Jinými slovy – '' |
| ===== 4. Podpora paralelního programování v OpenMP ===== | ===== 4. Podpora paralelního programování v OpenMP ===== | ||
| Line 333: | Line 333: | ||
| ==== Sériově-paralelní model uspořádání vláken (fork-join) ==== | ==== Sériově-paralelní model uspořádání vláken (fork-join) ==== | ||
| - | Fork-join model je základní exekuční schéma OpenMP. Program začíná jedním *master* vláknem, které po vstupu do direktivy **`parallel`** vytvoří tým dalších vláken (*fork*). Všechna vlákna spolupracují v daném paralelním regionu a na jeho konci se implicitní bariérou zase spojí do jediného vlákna (*join*). | + | Fork-join model je základní exekuční schéma OpenMP. Program začíná jedním *master* vláknem, které po vstupu do direktivy **'' |
| * Výhody: | * Výhody: | ||
| * jednoduchá správa vláken | * jednoduchá správa vláken | ||
| Line 358: | Line 358: | ||
| Další možnosti a doplňky modelu: | Další možnosti a doplňky modelu: | ||
| - | * `#pragma omp barrier` – ruční synchronizační bod. | + | * '' |
| - | * `single`, `master` – sekci vykoná pouze jedno vlákno. | + | * '' |
| - | * `ordered` – zachování pořadí iterací ve smyčce. | + | * '' |
| - | * `critical`, `atomic` – zajištění sériového přístupu ke sdíleným proměnným. | + | * '' |
| - | * `nowait` – zabrání implicitní bariéře na konci paralelního bloku. | + | * '' |
| - | * `OMP_NESTED=TRUE` nebo `omp_set_max_active_levels()` – aktivuje vnořenou paralelizaci. | + | * '' |
| - | * `task`, `taskgroup`, `depend(...)` – jemné řízení závislostí mezi úlohami (viz níže). | + | * '' |
| ==== Paralelizovatelná úloha (task region) ==== | ==== Paralelizovatelná úloha (task region) ==== | ||
| - | Pomocí direktivy | + | Pomocí direktivy |
| - | * Tasky lze organizovat do `taskgroup`. | + | * Tasky lze organizovat do '' |
| - | * Pomocí | + | * Pomocí |
| - | * `detach`, `priority` – umožňují pokročilou kontrolu provádění. | + | * '' |
| Příklad: | Příklad: | ||
| Line 387: | Line 387: | ||
| Přehled nejznámějších implementací (stav 2025):* | Přehled nejznámějších implementací (stav 2025):* | ||
| - | * **GCC 14+ (libgomp)** – `-fopenmp`, verze 5.2 (téměř úplná), open-source klasika. | + | * **GCC 14+ (libgomp)** – '' |
| - | * **Clang 18+ (libomp)** – `-fopenmp`, verze 5.2 (většina), | + | * **Clang 18+ (libomp)** – '' |
| - | * **Intel oneAPI (icx/icpx + iomp5)** – `-qopenmp`, verze 5.2, velmi výkonný runtime, podpora GPU. | + | * **Intel oneAPI (icx/icpx + iomp5)** – '' |
| - | * **IBM XL (LLVM-based)** – `-qsmp=omp`, verze 5.1, optimalizace pro POWER. | + | * **IBM XL (LLVM-based)** – '' |
| * **AMD AOCC 4.x** – laděno pro AMD Zen, Clang + libomp. | * **AMD AOCC 4.x** – laděno pro AMD Zen, Clang + libomp. | ||
| * **Cray/ | * **Cray/ | ||
| ==== Přehled hlavních direktiv OpenMP ==== | ==== Přehled hlavních direktiv OpenMP ==== | ||
| - | **`#pragma omp parallel`** | + | **'' |
| * Vytvoří tým vláken. | * Vytvoří tým vláken. | ||
| - | * Podporuje: | + | * Podporuje: |
| - | **`for` / `do`** | + | **'' |
| * Paralelizace smyčky. | * Paralelizace smyčky. | ||
| - | * Možnosti: | + | * Možnosti: |
| - | **`sections` / `section`** | + | **'' |
| * Spustí nezávislé bloky kódu paralelně (např. různé funkce najednou). | * Spustí nezávislé bloky kódu paralelně (např. různé funkce najednou). | ||
| - | **`task`** | + | **'' |
| - | * Vytvoří úlohu; možnost specifikace závislostí přes `depend(...)`. | + | * Vytvoří úlohu; možnost specifikace závislostí přes '' |
| - | * Další klauzule: | + | * Další klauzule: |
| - | **`barrier`** | + | **'' |
| * Explicitní synchronizační bod – všechna vlákna musí dojít na toto místo. | * Explicitní synchronizační bod – všechna vlákna musí dojít na toto místo. | ||
| - | **`critical [(name)]`** | + | **'' |
| * Zamezí více vláknům vstup do stejné sekce kódu najednou. | * Zamezí více vláknům vstup do stejné sekce kódu najednou. | ||
| * Jméno odděluje různé nezávislé sekce. | * Jméno odděluje různé nezávislé sekce. | ||
| - | **`atomic`** | + | **'' |
| * Odlehčená synchronizace pro jednoduché operace s proměnnou (inkrementace, | * Odlehčená synchronizace pro jednoduché operace s proměnnou (inkrementace, | ||
| Line 443: | Line 443: | ||
| </ | </ | ||
| - | Tento příklad ukazuje vytvoření tasku se závislostí | + | Tento příklad ukazuje vytvoření tasku se závislostí |
| Line 451: | Line 451: | ||
| ==== Statické × dynamické rozdělení práce ==== | ==== Statické × dynamické rozdělení práce ==== | ||
| * **Statické rozdělení** – práce (např. iterace smyčky) se rozdělí předem mezi všechna vlákna. | * **Statické rozdělení** – práce (např. iterace smyčky) se rozdělí předem mezi všechna vlákna. | ||
| - | * Např. pomocí | + | * Např. pomocí |
| * Výhodou je **nízký overhead** (prakticky žádná synchronizace). | * Výhodou je **nízký overhead** (prakticky žádná synchronizace). | ||
| * Nevýhodou je, že **u nepravidelných úloh může být některé vlákno přetížené**, | * Nevýhodou je, že **u nepravidelných úloh může být některé vlákno přetížené**, | ||
| * **Dynamické rozdělení** – práce se přiděluje **za běhu** podle toho, které vlákno je volné. | * **Dynamické rozdělení** – práce se přiděluje **za běhu** podle toho, které vlákno je volné. | ||
| - | * Používá se `schedule(dynamic[, | + | * Používá se '' |
| * Výhodou je lepší **vyvážení zátěže**. | * Výhodou je lepší **vyvážení zátěže**. | ||
| * Nevýhodou je **vyšší režie kvůli synchronizaci**. | * Nevýhodou je **vyšší režie kvůli synchronizaci**. | ||
| * **Guided plánování** – kompromis mezi statickým a dynamickým: | * **Guided plánování** – kompromis mezi statickým a dynamickým: | ||
| - | * `schedule(guided[, | + | * '' |
| * Vhodné pro případy, kdy práce trvá různě dlouho a časem ubývá. | * Vhodné pro případy, kdy práce trvá různě dlouho a časem ubývá. | ||
| * Další možnosti: | * Další možnosti: | ||
| - | * `schedule(runtime)` – výběr plánování je ponechán na hodnotě proměnné | + | * '' |
| - | * `schedule(auto)` – nechá výběr plánu na implementaci OpenMP. | + | * '' |
| ==== Thread-pool a fronta úkolů (work-stealing) ==== | ==== Thread-pool a fronta úkolů (work-stealing) ==== | ||
| Line 476: | Line 476: | ||
| Vyrovnané rozdělení práce je klíčem k výkonu paralelního programu. | Vyrovnané rozdělení práce je klíčem k výkonu paralelního programu. | ||
| * U **smyček**: | * U **smyček**: | ||
| - | * Volba správného | + | * Volba správného |
| - | * Velikost | + | * Velikost |
| - | * `collapse(n)` – slučuje více vnořených smyček do jedné, čímž zvyšuje počet iterací pro paralelizaci. | + | * '' |
| * U **tasků**: | * U **tasků**: | ||
| * Work-stealing pomáhá s dynamickým plánováním. | * Work-stealing pomáhá s dynamickým plánováním. | ||
| - | * Pomocí | + | * Pomocí |
| * Heuristiky runtime mohou **omezit vznik malých tasků** (např. jejich inline-ing) → lepší škálování. | * Heuristiky runtime mohou **omezit vznik malých tasků** (např. jejich inline-ing) → lepší škálování. | ||
| ==== Závislosti (dependencies) ==== | ==== Závislosti (dependencies) ==== | ||
| - | Tasky mohou mít mezi sebou **závislosti**, | + | Tasky mohou mít mezi sebou **závislosti**, |
| * Typy závislostí: | * Typy závislostí: | ||
| - | * `depend(in: X)` – task **potřebuje** data `X`. | + | * '' |
| - | * `depend(out: X)` – task **produkuje** data `X`. | + | * '' |
| - | * `depend(inout: | + | * '' |
| - | * Další pokročilé typy: `mutexinoutset`, `depobj` – pro specializované scénáře. | + | * Další pokročilé typy: '' |
| Ukázkový kód: | Ukázkový kód: | ||
| Line 510: | Line 510: | ||
| ===== 6. Techniky dekompozice programu na příkladech ===== | ===== 6. Techniky dekompozice programu na příkladech ===== | ||
| - | Abychom lépe pochopili různé způsoby paralelizace, | + | Abychom lépe pochopili různé způsoby paralelizace, |
| ==== Řazení ==== | ==== Řazení ==== | ||
| Line 520: | Line 520: | ||
| * *Conquer*: obě části rekurzivně řadíme – ideální místo pro vytvoření dvou paralelních úloh (*tasků*). | * *Conquer*: obě části rekurzivně řadíme – ideální místo pro vytvoření dvou paralelních úloh (*tasků*). | ||
| * *Combine*: není třeba – dělení samo zajistí správné pořadí. | * *Combine*: není třeba – dělení samo zajistí správné pořadí. | ||
| - | * Paralelizace: | + | * Paralelizace: |
| <code cpp> | <code cpp> | ||
| Line 546: | Line 546: | ||
| * *Divide*: rekurzivní dělení pole na půlky. | * *Divide*: rekurzivní dělení pole na půlky. | ||
| * *Conquer*: každou půlku řadíme paralelně. | * *Conquer*: každou půlku řadíme paralelně. | ||
| - | * *Combine*: dvě seřazené části spojíme lineárním | + | * *Combine*: dvě seřazené části spojíme lineárním |
| - | * Paralelizace: | + | * Paralelizace: |
| <code cpp> | <code cpp> | ||
| Line 575: | Line 575: | ||
| * *Divide*: rozdělíme po řádcích. | * *Divide*: rozdělíme po řádcích. | ||
| * *Conquer*: každý řádek počítá vlákno nezávisle. | * *Conquer*: každý řádek počítá vlákno nezávisle. | ||
| - | * *Combine*: nepotřebujeme – každý výstupní | + | * *Combine*: nepotřebujeme – každý výstupní |
| * U husté matice: nejlepší přístup po řádcích (row-major). | * U husté matice: nejlepší přístup po řádcích (row-major). | ||
| * U řídké: paralelizace přes nenulové řádky (např. CSR formát). | * U řídké: paralelizace přes nenulové řádky (např. CSR formát). | ||
| Line 598: | Line 598: | ||
| * **Blokové (tiling) násobení**: | * **Blokové (tiling) násobení**: | ||
| * *Divide*: rozdělíme výstupní matici $C$ na bloky $B_{pq}$. | * *Divide*: rozdělíme výstupní matici $C$ na bloky $B_{pq}$. | ||
| - | * *Conquer*: každý blok počítá vlákno/ | + | * *Conquer*: každý blok počítá vlákno/ |
| * *Combine*: není třeba – bloky jsou oddělené. | * *Combine*: není třeba – bloky jsou oddělené. | ||
| Line 614: | Line 614: | ||
| * **Gaussova eliminace (LU)**: v kroku $k$ odstraňujeme hodnoty pod pivotem $A_{kk}$. | * **Gaussova eliminace (LU)**: v kroku $k$ odstraňujeme hodnoty pod pivotem $A_{kk}$. | ||
| * Paralelizujeme řádky $i = k+1..n-1$. | * Paralelizujeme řádky $i = k+1..n-1$. | ||
| - | * Nutná synchronizace mezi kroky – `taskwait` nebo sekvenční závislosti. | + | * Nutná synchronizace mezi kroky – '' |
| <code cpp> | <code cpp> | ||
| Line 630: | Line 630: | ||
| * **Iterativní metody (Jacobi, CG, GMRES)**: | * **Iterativní metody (Jacobi, CG, GMRES)**: | ||
| - | * Lépe paralelizovatelné než Gauss – hlavně | + | * Lépe paralelizovatelné než Gauss – hlavně |
| - | * OpenMP poskytuje | + | * OpenMP poskytuje |
| * **Off-load na GPU (OpenMP 5.x)**: | * **Off-load na GPU (OpenMP 5.x)**: | ||
| - | * Pomocí | + | * Pomocí |
| * Host kontroluje synchronizaci, | * Host kontroluje synchronizaci, | ||
| Line 756: | Line 756: | ||
| Každý proces $p_i$ periodicky: | Každý proces $p_i$ periodicky: | ||
| - | - Posílá | + | - Posílá |
| - | - Pokud žádná odpověď nepřijde, požádá $\mathcal{K}$ jiných uzlů, aby se zeptaly místo něj (`ping_req`). | + | - Pokud žádná odpověď nepřijde, požádá $\mathcal{K}$ jiných uzlů, aby se zeptaly místo něj ('' |
| - | - Tyto uzly pingnou $p_j$, a pokud odpověď dostanou, pošlou ji zpět $p_i` jako `ping_ack`. | + | - Tyto uzly pingnou $p_j$, a pokud odpověď dostanou, pošlou ji zpět $p_i'' |
| - Pokud nikdo z $\mathcal{K}$ nedostane odpověď → $p_j$ je označen za mrtvého. | - Pokud nikdo z $\mathcal{K}$ nedostane odpověď → $p_j$ je označen za mrtvého. | ||
| Line 904: | Line 904: | ||
| **Základní princip:** | **Základní princip:** | ||
| * Procesy si **lokálně zaznamenají** svůj stav. | * Procesy si **lokálně zaznamenají** svůj stav. | ||
| - | * Stav kanálů mezi nimi se zjistí pomocí **speciální zprávy**: | + | * Stav kanálů mezi nimi se zjistí pomocí **speciální zprávy**: |
| * Algoritmus je **asynchronní** a **neblokující** – každý proces koná na základě přijatých značek. | * Algoritmus je **asynchronní** a **neblokující** – každý proces koná na základě přijatých značek. | ||
| **Průběh: | **Průběh: | ||
| - | - Jeden proces iniciuje snapshot – uloží si stav a pošle | + | - Jeden proces iniciuje snapshot – uloží si stav a pošle |
| - | - Když jiný proces obdrží | + | - Když jiný proces obdrží |
| * uloží svůj stav, | * uloží svůj stav, | ||
| - | * pošle | + | * pošle |
| * vše, co do té doby přišlo na kanálu, **patří do snapshotu**. | * vše, co do té doby přišlo na kanálu, **patří do snapshotu**. | ||
| - | - Pokud přijde | + | - Pokud přijde |
| Výsledkem je **konzistentní globální snapshot**. | Výsledkem je **konzistentní globální snapshot**. | ||
| Line 949: | Line 949: | ||
| * V distribuovaném prostředí je nutné **synchronizovat přístup přes zprávy**. | * V distribuovaném prostředí je nutné **synchronizovat přístup přes zprávy**. | ||
| * Algoritmus poskytuje dvě základní operace: | * Algoritmus poskytuje dvě základní operace: | ||
| - | * `enter()` – požádá o vstup do kritické sekce | + | * '' |
| - | * `exit()` – opustí kritickou sekci | + | * '' |
| ==== Požadavky na algoritmus pro vyloučení procesů ==== | ==== Požadavky na algoritmus pro vyloučení procesů ==== | ||
| Line 998: | Line 998: | ||
| * frontu odložených žádostí | * frontu odložených žádostí | ||
| * Pro vstup do kritické sekce: | * Pro vstup do kritické sekce: | ||
| - | * proces pošle | + | * proces pošle |
| - | * čeká na odpovědi | + | * čeká na odpovědi |
| * Ostatní procesy odpoví podle kauzálního (Lamportova) času | * Ostatní procesy odpoví podle kauzálního (Lamportova) času | ||
| Line 1042: | Line 1042: | ||
| * Procesy jsou logicky uspořádány do kruhu (např. podle ID). Každý zná svého následníka a umí ho kontaktovat. | * Procesy jsou logicky uspořádány do kruhu (např. podle ID). Každý zná svého následníka a umí ho kontaktovat. | ||
| * Při podezření na pád lídra (např. po timeoutu) proces $P_i$ zahájí volby: | * Při podezření na pád lídra (např. po timeoutu) proces $P_i$ zahájí volby: | ||
| - | * pošle | + | * pošle |
| - | * pokud příjemce dostane | + | * pokud příjemce dostane |
| * pokud $j > i$, předá dál beze změny, | * pokud $j > i$, předá dál beze změny, | ||
| * pokud $j < i$, nahradí vlastním ID a pošle dál, | * pokud $j < i$, nahradí vlastním ID a pošle dál, | ||
| * pokud $j = i$, zpráva oběhla kruh ⇒ $P_i$ má nejvyšší ID ⇒ vítězí. | * pokud $j = i$, zpráva oběhla kruh ⇒ $P_i$ má nejvyšší ID ⇒ vítězí. | ||
| - | * Nový lídr pak vyšle | + | * Nový lídr pak vyšle |
| **Vlastnosti: | **Vlastnosti: | ||
| Line 1058: | Line 1058: | ||
| * Procesy jsou propojeny do **úplné sítě** – každý zná každého. | * Procesy jsou propojeny do **úplné sítě** – každý zná každého. | ||
| * Pokud $P_i$ zjistí, že koordinátor mlčí (timeout), zahájí volby: | * Pokud $P_i$ zjistí, že koordinátor mlčí (timeout), zahájí volby: | ||
| - | - Pošle | + | - Pošle |
| - Pokud žádný neodpoví → $P_i$ se **prohlásí lídrem** | - Pokud žádný neodpoví → $P_i$ se **prohlásí lídrem** | ||
| - | - Pošle | + | - Pošle |
| - | - Pokud někdo odpoví | + | - Pokud někdo odpoví |
| - Pokud neobdrží oznámení včas, znovu zahájí volby | - Pokud neobdrží oznámení včas, znovu zahájí volby | ||
| **Zprávy: | **Zprávy: | ||
| - | * `ELECTION` – „ozvi se, pokud žiješ a jsi silnější“ | + | * '' |
| - | * `OK` – potvrzení, že někdo silnější žije | + | * '' |
| - | * `COORDINATOR(k)` – oznámení o novém lídrovi | + | * '' |
| **Vlastnosti: | **Vlastnosti: | ||