Programování v UNIXu - cvičení

---------------------------------------------------------------------------
14.12.2005, 21.12.2005 - synchronizace vláken
---------------------------------------------------------------------------
- napište program, který pomocí mutexů a podmínkových proměnných
  implementuje bariéru, a to tímto způsobem:

  - vytvořte několik vláken (alespoň 5)
  - v každém vlákně simulujte činost tak, že ho uspíte na náhodně zvolenou
    dobu funkcí random(), horní limit stačí třeba 10 sekund.
  - po probuzení, které zde znamená, že vlákno vykonalo požadovanou práci a
    a že se dostalo k bariéře, snižte globální proměnnou obsahující počet
    pracujících vláken. Pak se uspěte na podmínkové proměnné. Předtím ještě
    toto vlákno oznámí na terminál, že dosáhlo bariéry.
  - to vlákno, které sníží tuto proměnnou na 0, sdělí broadcastem ostatním,
    že všechna vlákna dosáhla bariéry.  Ještě předtím toto poslední vlákno
    vypíše na terminál, že všechna vlákna jsou na bariéře.
  - po probuzení na bariéře všechna vlákna vypíší hlášku o pokračování v
    práci a hned skončí

Výstup tedy musí vypadat tak, že na začátku v různých intervalech vlákna
hlásí, že dosáhla bariéry. Poslední vlákno poté zahlásí, že všechna vlákna
jsou na bariéře. Následně na to se musí objevit hlášky od všech vláken, že
pokračují. Tyto hlášky se musí objevit ,,najednou''.

Dejte pozor na správné použití mutexů, čekání na podmínkových proměnných
vždy implementujte v cyklu, a zajistěte, aby vlákno main() neskončilo dříve,
než ostatní vlákna.

---------------------------------------------------------------------------
30.11.2005, 7.12.2005 - síťová komunikace, vlákna
---------------------------------------------------------------------------
- napište TCP server, který ve smyčce akceptuje příchozí požadavky na
  spojení. Pro každé spojení vytvoří vlákno, které se postará o příjem dat a
  jejich následné vrácení klientovi, bez změn. Server jako svůj jediný
  parametr akceptuje číslo portu.

  jako klienta je možné použít program telnet (např. telnet localhost 2600).
  Zkuste si pustit klienta z alespoň dvou terminálů najednou, abyste
  ověřili, že server obsluhuje požadavky v separátních vláknech.

  server pak přeložte na Solarisu a funkčnost ověřte stejným způsobem jako
  na mašinách v labu.

  nezapoměnte detachovat vlákna obsluhující jednotlivá TCP spojení

---

- vytvořte dvě nová vlákna. V hlavním a prvním vlákně zamaskujte všechny
  signály, v prvním vlákně pak skočte do smyčky a každou sekundu něco
  vypište, třeba tečku, bez znaku nového řádku. Main vlákno se uspí na
  pthread_join(). Funkce druhého vlákna bude obsluha signálů, tj. zablokujte
  také všechny signály ktere chcete zpracovavat (abyste nejaky neztratili
  nebo aby vas neukoncil driv nez zavolate sigwait - tady by se to nestalo,
  ale v praxi se to stat muze) a po návratu z volání sigwait() vypište na
  terminál číslo signálu, které jste zachytili. Signály posílejte z jiného
  terminálu pomocí příkazu kill(1).

---------------------------------------------------------------------------
23.11.2005 - mapování souborů, signály
---------------------------------------------------------------------------

Jako 16.11.2005.

---------------------------------------------------------------------------
16.11.2005 - mapování souborů, signály
---------------------------------------------------------------------------

- nastavte si signál handler pro zachycení Ctrl-C (SIGINT). Při zachycení
  signálu pouze tuto skutečnost vypište, použijte pro to signal safe funkci,
  třeba write(1, ...). Ve smyčce pak volejte sleep(1) a ověřte, že po stisku
  Ctrl-C se váš program chová tak jak má - tedy pro každý Ctrl-C vypíše
  příslušnou hlášku.

---------------------------------------------------------------------------

- v hlavním procesu si namapujte nějaký soubor. Poté přes fork() vytvořte
  nový proces. V otci přečtěte jeden znak z terminálu (stačí pres read(0,
  ...)), tento znak zapište do 1. bajtu namapovaného souboru a poté pošlete
  synovi USR2 signál, kterým mu oznámíte, že příslušný znak je uložen v
  paměti.

- syn čeká pomocí sigwait() dokud nepřijde signál USR2, poté vypíše znak,
  který mu otec zapsal do namapované paměti.

- je nutné už v otci zablokovat signál USR2, protože kdyby syn tento signál
  dostal dříve než zavolá sigwait(), zabilo by ho to.

---------------------------------------------------------------------------
9.11.2005 - fork(), pipe()
---------------------------------------------------------------------------

- vytvořte postupně 3 procesy tak, že třetí je potomek druhého a druhý
  prvního. Vytvořte nepojmenované roury mezi prvním a druhý, mezi druhým a
  třetím procesem. Zduplikujte deskriptory tak, že standardní vstup prvního
  a standardní výstup druhého procesu používá první rouru, standardní vstup
  druhého a standardní výstup třetího procesu používá druhou rouru.

- třetí proces zapíše několikrát (číslo si zvolte, hodnota není důležitá) na
  stdout (tj. do druhé roury) svůj PID a pak zavře stdout, druhý proces
  příslušné PID přečte z stdin tolikrát kolikrát může (tj. čte tak dlouho,
  dokud není pajpa prázdná - počet musí být stejný jako počet zápisů),
  zapíše je stejným způsobem na stdout a pak také zavře svůj stdout. První
  proces dané PID přečte z stdin tolikrát kolik jich v pajpě je a pokaždé je
  vypíše na terminál. Pak skončí.

- pro čtení a zápis používejte standarní volání read() a write()

- před skončením druhého a třetího procesu zavolejte sleep(5). Pokud první
  proces také čeká 5 sekund, než skončí a teprve pak se objeví prompt
  shellu, tak jste nezavřeli všechny deskriptory tak, jak jste měli, tj.
  uspali jste se při čtení pajpy, která je sice prázdná, ale má ji ještě
  někdo otevřenou pro zápis. Požadované chování je, že první proces musí
  dostat konec pajpy hned po přečtení příslušného počtu PID čísel, ne až po
  skončení ostatních procesů.

- můžete daný příklad udělat nejdříve se dvěma procesy, pokud se vám to zdá
  jednodušší
  

---------------------------------------------------------------------------
2.11.2005
---------------------------------------------------------------------------

Byl místo mě Honza Chadima.

---------------------------------------------------------------------------
26.10.2005
---------------------------------------------------------------------------

Zadání stejné jako 19.10.2005.

---------------------------------------------------------------------------
19.10.2005 - pojmenované roury, read(), write(), getopt()
---------------------------------------------------------------------------

- napište program, který vytvoří pojmenovanou rouru (tj. FIFO) příkazem
  mkfifo(), otevře ji zvlášť pouze pro zápis a zvlášť pouze pro
  čtení, zapíše do ní jistý počet znaků a pomocí druhého deskriptoru je
  přečte. Pro cestu k rouře, počet znaků i konkrétní znak použijte vámi
  zvolenou default hodnotu pokud nebude zadána na příkazovém řádku. 

  -f <fifo>
  -n <number>
  -c <character>

  pro zpracování přepínačů použijte samozřejmě fci getopt. Pro konkrétní
  informace ohledně chování systémových volání vzhledem k rouře použijte
  manuálové stránky na Solarisu (jsou podrobnější než na Linuxu, FreeBSD)
  nebo normu UNIX03 (www.unix.org).

  program musí být robustní, tj. vypořádat se se situacemi, kdy např.
  nelze vytvořit rouru (/root/my-fifo) atd.

Na doma:
--------
- to samé jako předtím, ale použijte dup() volání a pak čtěte z roury přes
  standardní vstup a pište do roury přes standardní výstup.

- na příkazové řádce definujte soubor, který vypište po znacích pozadu.
  Udělejte to tak, že odzadu postupně načítejte data do 10-ti bajtového
  bloku a z toho pak znaky vypište na výstup.

- přepínačem -o si definujte výstupní soubor, ostatní parametry berte jako
  vstupní soubory, které postupně zapíšete do výstupního souboru, tj.
  výstupní soubor bude spojením vstupních souborů. Pokud výstupní soubor
  existuje, zrušte nejdříve jeho obsah.