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 pipe a dup2) 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ódem 1, v opačném případě vypíše tamtéž řádku “OK” a skončí s kódem 0.

  • 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 count následovaným hodnotou celočíselného čítače čítajícího od 0 (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ím fflush(stdout) a počká 1 sekundu příkazem sleep(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ódem 0.

  • XXD začne vykonávat program xxd -p, např. voláním funkce execlp.

Dále vytvořte Makefile, který:

  • Zkompiluje váš program a binárku forkpipe umístí do stejného adresáře jako soubor Makefile.
  • 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.toml uvedete:

    [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 (v Makefile).

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

Je na stránce chyba?

Edit Upravit tuto stránku

Máte otázky nebo připomínky?

Edit Dejte nám vědět