6. týždeň

Medziprocesová komunikácia - Rúry

Ciele

  1. Oboznámiť sa s pojmom medziprocesová komunikácia
  2. Zistiť, ako fungujú rúry
  3. Naučiť sa pracovať s nepomenovanými rúrami
  4. Naučiť sa pracovať s pomenovanými rúrami

Postup

Krok 1: Medziprocesová komunikácka

Príprava

Pre prácu na cvičení si stiahnite súbor k cvičeniu.

Obsah súboru:

.
└── 06
    ├──u1_1.c
    ├──u2_1.c
    ├──Makefile
    └──tests
       ├──u1_1_test.sh
       └──u2_1_test.sh

Poznámka

Programy je možné kompilovať pomocou make nazov_suboru.c Napríklad: make u1_1.c

Úvod

V operačnom systéme UNIX/Linux sú všetky procesy chápané ako entity, ktoré sú nezávislé. Tieto procesy nedokážu komunikovať s inými procesmi, ktoré sú v danej chvíli spracovávané.

Medziprocesová komunikácia (IPC) umožňuje rôznym procesom navzájom komunikovať s tým, že zabezpečuje výmenu dát a synchronizáciu ich spracovania.

Existuje niekoľko prístupov medziprocesovej komunikácie:

  • Signály - neposielajú sa žiadne dáta. Jedná sa len o spôsob upozornenia procesu. Signály môžu zasielať buď procesy alebo ich môže vyvolať samotné jadro.
  • Rúry - najstarší komunikačný mechanizmus vo všetkých typoch UNIX-ov.
    • nepomenované rúry - umožňujú komunikovať len príbuzným procesom.
    • pomenované rúry - umozňujú komunikáciu aj procesom, ktoré nie sú príbuzné.
  • Sockety - umožňujú medziprocesovú komunikáciu nielen na lokálnej úrovni v rámci toho istého hostiteľského počítača ale vďaka použitiu komplikovanejších sieťových protokolov aj procesom na rôznych hostiteľoch spôsobom klient-server.
  • System V IPC - obsahuje mechanizmy komunikácie známe z komerčných implementácií UNIX/Linux-u, ako sú mechanizmy frontov správ umožňujúcich procesom zasielať formátované postupnosti dát, zdieľanej pamäte, keď procesy môžu zdieľať časti ich virtuálneho adresného priestoru a semaforov, pomocou ktorých procesy synchronizujú svoju činnosť.
    • Semafory
    • Zdieľaná pamäť
    • Fronty správ

Krok 2: Rúry

Teória

Existujú: nepomenované rúry pomenované rúry (FIFO)

Uveďte skratku kategórie systémových prostriedkov, do ktorej patrí mechanizmus signálov:

Správna odpoveď: IPC - Medziprocesová komunikácia
Nesprávna odpoveď

Krok 3: Nepomenované rúry

Opis

Umožňujú komunikáciu medzi dvoma procesmi, ktoré musia byť vzájomne príbuzné. To znamená, že medzi nimi musí byť vzťah typu rodič-potomok aj keď sa nemusí jednať o bezprostredného potomka.

Princíp komunikácie pomocou nepomenovaných rúr

Údaje sa zapisujú na zapisovacom konci rúry a následne sú prečítané na čítacom konci. Jedná sa o sériovú komunikáciu - v takom poradí, v akom boli údaje zapísané na jednom konci sú na druhom prečítané.

Nevýhody:

  • jednosmerný tok dát
  • komunikácia len medzi príbuznými procesmi (vytvorené rúry zdedí každý potomok)
  • jedná sa o samosynchronizujúci prostriedok ale len v prípade jedného volania jadra pre čítanie. Ak sa čítanie rozdelí na viac volaní, tak môže dochádzať ku konfliktom medzi procesmi.

Služba jadra pipe()

Rúra sa vytvorí volaním služby pipe(). Po volaní služby pipe() sa v prvom prvku poľa nachádza deskriptor pre čítanie z rúry (file[0]) a v druhom prvku deskriptor pre zápis do rúry (file[1]).

#include <unistd.h>

int pipe (int file[2]);
Parametere
int file[2] argumentom služby pipe() je celočíselné pole s 2 prvkami. Toto pole služba pipe() vyplní dvoma novými deskriptormi (pre zápis a pre čítanie)
Návratová hodnota
Pri úspešnom vykonaní vráti 0
Pri chybe -1.

Úloha 3.1

Pre podrobnejšie vysvetlenie služby pipe() navštívte manuál man 2 pipe

Príklad použitia:

#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>

#define BUFSIZE 5

int main(){
    int file[2];
    int bytes;
    char data[] = "text";
    int length = strlen(data);
    char buffer[BUFSIZ + 1];
    memset(buffer, '\0', sizeof(buffer));

    if(pipe(file) == 0){
        bytes = write(file[1], data, length);
        printf("Zapis %d bytov do rury.\n", bytes);
        bytes = read(file[0], buffer, BUFSIZE);
        printf("Citanie %d bytov z rury. Obsah: %s.\n", length, buffer);
        exit(EXIT_SUCCESS);
    }
    exit(EXIT_FAILURE);
}
Vysvetlenie
int data_processed - premenná do ktorej je najprv uložený počet zapísaných bytov a neskôr počet prečítaných bytov
int file_pipes[2] - dvojprvkové celočíselné pole do ktorého služba pipe() uloží 2 nové deskriptory (na indexe [0] sa nachádza deskriptor pre čítanie z rúry a na indexe [1] sa nachádza deskriptor pre zápis do rúry)
memset(buffer, '\0', sizeof(buffer)); - funkcia memset() vyplní počet bytov (sizeof(buffer)) poľa buffer vzorom uloženým v 2 parametri ('\0')
Najprv sa do premennej data_processed zapíše počet zapísaných bytov pomocou služby write() a následne sa do nej zapíše počet prečítaných bytov pomocou služby read().

Výstup z programu:

Zapis 4 bytov do rury.
Citanie 4 bytov z rury. Obsah: text.

Služba pipe() okrem tradičnej návratovej hodnoty vracia aj ďalšie dáta. Aký je typ návratovej hodnoty z týchto dátových položiek?

Odoslať odpoveď
Správna odpoveď: int
Nesprávna odpoveď

Úloha 3.2

Vytvorte program, ktorý vytvorí nepomenovanú rúru. Následne vytvorí proces potomka pomocou služby fork(). V procese potomka zapíše do rúry reťazec znakov "operacne systemy". V procese rodiča tento reťazec znakov prečítajte a vypíšte ho v tvare: Precitany retazec znakov: operacne systemy s dlzkou 17.

Poznámka

Zdrojové súbory k úlohe sa nachádzajú v priečinku 06 pod názvom u1_1.c. Pred testovaním je potrebné skompilovať program u1_1.c. Úlohu je možné testovať zadaním následovného príkazu do terminálu: ./tests/u1_1_test.sh

Ktorý z uvedených príznakov (flag) služby open() charakterizuje filedes[1]?

Správna odpoveď: O_WRONLY - keďže sa jedná o koniec rúry určený na zapisovanie.
Nesprávna odpoveď

Krok 4: Pomenované rúry (FIFO)

Opis

Pomenované rúry majú podobné správanie ako nepomenované ale existujú ako záznam v súborovom systéme. Vďaka tomu vedia k ním prístupovať procesy na základe mena tohto súboru.

Poznámka

Na rozdiel od nepomenovaných rúr, pomenované rúry môžu využívať aj procesy, ktoré sú navzájom nezávislé (nejedná sa o rodičovské procesy a ich potomkov).

FIFO musí byť otvorené na oboch koncoch (zápis aj čítanie) predtým než môže odovzdávať dáta. V prípade, že nie je, tak je blokované.

Služba jadra mkfifo()

Služba jadra mkfifo() slúži na vytvorenie pomenovanej rúry.

#include <sys/type.h>
#include <sys/stat.h>

int mkfifo(const char *pathname, mode_t mode);
Parametere
const char *pathname názov súboru, ktorý bude slúžiť ako referenčný bod, ktorým procesy môžu pristupovať k rúre
mode_t mode prístupové práva
Návratová hodnota
Pri úspešnom vykonaní vráti 0
Pri chybe -1.

Úloha 4.1

Pre podrobnejšie vysvetlenie služby mkfifo() navštívte manuál man 2 mkfifo

Aplikovanie poznatkov k službe mkfifo()

Príklad použitia:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>

int main(){
    int des_fifo;
    des_fifo = mkfifo("/tmp/my_fifo", 0777);
    printf("Hodnota premennej des_fifo je %d\n", des_fifo);
    if(des_fifo==0){
        printf("Uspesne sa podarilo vytvorit FIFO.\n");
    } 
    else{
        perror("Chyba:");
    } 
   return 0;
}

Výstup z programu:

des_fifo je 0
Uspesne sa podarilo vytvorit FIFO

Záznam o vytvorení rúry sa dá nájsť pomocou:

ls -lF /tmp/my_fifo

Výpis vyzerá priblížne takto: (u každého sa bude líšiť)

prwxr-xr-x 1 ab123yz tuke 0 Jan 10 10:10 /tmp/my_fifo|

Na začiatku výpisu sa nachádza písmeno p. To znamená, že sa jedná o rúru. Symbol | na konci sa nachádza kvôli voľbe F príkazu ls a tiež označuje rúru.

Upozornenie

V prípade, že program spustíte opäť, tak nedôjde k vytvoreniu rúry, pretože už v systéme existuje. Výstup v tom prípade bude:

des_fifo je -1
Chyba:: File exists

Vytvorenú rúru je možné odstrániť pomocou služby jadra unlink(). V prípade, aký bol uvedený v príklade použitia, je potrebné zadať:

unlink /tmp/my_fifo

Ďalšie poznatky k rúram

Prístup k pomenovanej rúre

Pomenované rúry sú súčasťou súborového systému. Vďaka tomu je možné ich používať v príkazoch na mieste, kde sa bežne používa názov súboru.

Rozdiel medzi nepomenovanou a pomenovanou rúrou

Pomenovaná rúra Nepomenovaná rúra
existuje v podobe pomenovaného súboru existuje ako otvorený deskriptor súboru
je potrebné ju otvárať pred tým, ako sa do/z nej zapisujú/čítajú dáta dá sa s ňou pracovať len v aktuálnom procese, alebo v procese potomka

Pomenovaná rúra sa otvára/zatvára rovnakými funkciami open()/close(), ktoré boli použité pri otváraní/zatváraní súborov.

Ktorý systémový prostriedok využíva mechanizmus pipe (rúr) na dočasné uschovanie dát? (nominatív singuláru):

Správna odpoveď: pamäť
Nesprávna odpoveď

Záverečná úloha

Úloha 4.2

Vytvorte program, ktorý príjme ako argument reťazec znakov (ten sa automaticky uloží ako argv[1]). Následne si vytvorí pomenovanú rúru pomocou funkcie make_fifo(). K tejto rúre bude pristupovať pomocou deskriptoru (návratová hodnota funkcie make_fifo()) uloženého pod premennou file_descriptor vo funkciách write_fifo() a read_fifo(). Návratovou hodnotou funkcií write_fifo() a read_fifo() je počet zapísaných/prečítaných bytov. Vo funkcií main() po vytvorení pomenovanej rúry zapíšte do tejto rúry reťazec znakov a následne ho aj z tejto rúry prečítajte a vypíšte na štandardný výstup.

Poznámka

Zdrojové súbory k úlohe sa nachádzajú v priečinku 06 pod názvom u2_1.c. Pred testovaním je potrebné skompilovať program u2_1.c. Úlohu je možné testovať zadaním následovného príkazu do terminálu: ./tests/u2-1-test.sh