Procesy a meziprocesní komunikace#
Domácí příprava#
Předpokládáme, že máte základní znalosti jazyka C a víte, jak funguje překlad ze zdrojových kódů jazyka C do binární spustitelné aplikace (v obecném případě, kdy je zdrojových souborů více).
Dále byste měli umět použít překladač gcc včetně jeho základních
přepínačů a také byste měli znát nástroj make pro
automatizaci překladu programů v jazyku C/C++.
Dále je pro absolvování cvičení nutné mít přehled o systémových voláních fork, pipe, dup, open, kill, wait a execve, tzn. měli byste vědět, jak vzniká nový proces a jak lze přesměrovat standardní vstup a výstup. Potřebné informace se dozvíte na některé z předchozích přednášek.
Zadání úlohy#
Vytvořte v jazyce C, C++ nebo Rust program forkpipe, který:
-
Vytvoří dva procesy (potomky) voláním funkce
fork. Prvně vytvořený proces budeme níže nazývat GEN, druhý XXD. Původní (hlavní) proces bude dále označován jako MAIN. (POZOR, pro správné vyhodnocení záleží na pořadí vytvoření potomků.) -
Program tyto potomky propojí rourou (funkce
pipeadup2) tak, aby standardní výstup GEN byl napojen na standardní vstup XXD. -
Poté proces MAIN počká 5 sekund pomocí volání
sleep(5). -
Poté pošle procesu GEN signál
SIGTERM, který způsobí ukončení obou potomků.GEN skončí díky obsluze signálu – viz níže, XXD by pak měl skončit automaticky také, neboť při ukončení GEN OS uzavře rouru a XXD je naprogramován tak, že skončí při uzavření standardního vstupu.
-
MAIN následně počká na ukončení procesů GEN a XXD (např. pomocí funkce
wait). -
Pokud libovolný z potomků skončil chybou (návratový kód
!= 0), vypíše na standardní výstup řádku “ERROR” a skončí s návratovým kódem1, v opačném případě vypíše tamtéž řádku “OK” a skončí s kódem0. -
Pokud libovolné systémové volání vrátí chybu, aktuální proces okamžitě skončí s návratovým kódem
2. -
GEN bude na standardní výstup vypisovat řádky začínající textem
OSY countnásledovaným hodnotou celočíselného čítače čítajícího od0(např. pomocíprintf(“OSY count %d\n”, cnt++)). Po výpisu každého řádku proces GEN vynutí předání vypsaného textu jádru OS volánímfflush(stdout)a počká 1 sekundu příkazemsleep(1). -
GEN bude reagovat na signál
SIGTERM. Při zaslání tohoto signálu GEN vypíše na standardní chybový výstup řádku “GEN TERMINATED” a skončí s návratovým kódem0. -
XXD začne vykonávat program
xxd -p, např. voláním funkceexeclp.
Dále vytvořte Makefile, který:
- Zkompiluje váš program a binárku
forkpipeumístí do stejného adresáře jako souborMakefile. - Překladači jazyka C/C++ vždy předá volbu
-Wall, která způsobí výpis užitečných varování, a dále volby v proměnnéEXTRA_CFLAGS, která je ve výchozím stavu prázdná.
Poznámky k implementaci#
-
Rouru musíte vytvořit dříve než potomky, abyste je s ní mohli propojit.
-
Po vytvoření potomků rodičovský proces rouru nepotřebuje a měl by ji uzavřít. Pokud ji neuzavře, XXD neskončí automaticky po ukončení GEN, jak je popsáno výše, protože roura bude stále otevřená.
-
Uzavírejte důsledně všechny file descriptory, které již nebudete potřebovat. Předejdete tím záludným chybám.
-
Z funkce obsluhující signál (tzv. signal handler) není možné volat libovolnou funkci. Viz man signal-safety. Zejména by se nemělo používat “buffered I/O”, tedy např. funkce
printf. Pokud nepodporovanou funkci zavoláte, program může (ale nemusí) zhavarovat (jedná se o tzv. chybu souběhu neboli “race condition”). -
Pro ladění programu se vám může hodit příkaz
strace -f. Vyzkoušejte ho také s argumenty-e process,-e file,-e trace=dup2, apod. -
Odevzdávejte všechny soubory zabalené v archivu. Můžete použít příkaz
tar czf osy02.tgz Makefile *.[ch]tar czf osy02.tgz Makefile *.[ch] Cargo.toml src -
Pokud program implementujete v Rustu, můžete používat následující Crates a to tak, že v
Cargo.tomluvedete:[dependencies] nix = { version = "0.31.3", features = ["signal", "fs"] } libc = "0.2" anyhow = "1.0" lazy_static = "1.5"Ne všechny poskytnuté crates je nutné využít, správné řešení v Rustu může jít napsat i bez nich. Dostupné verze crates jsou dané tím, jaké verze byly použity při vytváření obrazu pro BRUTE a mohou být starší než ty, které používáte lokálně.
Program překládejte pomocí
cargo build --offline(vMakefile).
Ukázkový kód#
Jak vytvořit proces a rouru se můžete inspirovat ukázkovým kódem z manuálové stránky systémového volání pipe.
Domácí příprava na další cvičení#
Pro další cvičení budete potřebovat vědět
- co jsou vlákna,
- jaké problémy mohou nastávat při paralelním běhu vláken,
- jaké synchronizační prostředky máme k dispozici a
- jak je vytvoříme v jazyce C s využitím knihovny pthread.
Potřebné informace byste měli získat na přednáškách, případně se podívejte na