Způsoby komunikace procesů tak, jak je uvedla první veřejná verze UNIXu v r. 1979 (UNIX Version 7), byly uvedeny v kap. 2. Jejich používání jsme přitom předváděli v prostředí odpovídajícím současným obecným dokumentům SVID a POSIX. Byly uvedeny, protože úzce souvisí se vznikem a zařazením procesu do stromové struktury procesů. Jedná se o signály (čl. 2.2) a rouru (odst. 2.5.1). V původní koncepci byla přitom pouze roura zjevně navržena pro spojení dvou procesů a jednosměrný přenos dat mezi nimi.
Signály byly navrženy pro synchronizaci procesů při výskytu určité neobvyklé události v systému a pro samotný proces to znamenalo obvykle pokyn k ukončení, k čemuž skutečně došlo, pokud se proces sám dříve nerozhodl událost přežít. Signály souvisí také s existenční závislostí na rodiči procesu. Signál zaslaný vedoucímu skupiny procesů znamenal zánik celé skupiny. Teprve rozšíření UNIXu přineslo tlak na vývoj systému tak, že byly signály použity pro obecnou synchronizaci procesů. Byly zavedeny signály SIGUSR1, SIGUSR2 a další (z původního počtu 14 jich dnes SVID definuje celkem 28), jejichž vyslání v mnoha případech už neznamenalo ukončení cílového procesu v případě, že tento signál proces neočekával, ale např. jeho ignorování (viz Příloha B). Signály jsou dnes stále dominantní v synchronizaci procesů, ať už systémových nebo aplikačních. Problémy, které při jejich používání programátorům nastávají, vychází z jejich původní koncepce. Je např. obtížné zjistit obecně PID libovolného běžícího procesu. Proces má prostředky pro evidenci PID svých dětí (v návratové hodnotě fork), může zjistit své PID (getpid), svého rodiče (getppid) nebo vedoucího své skupiny (getpgrp), ale další prostředky nemá. Seznam procesů evidovaných jádrem včetně jejich PID lze pořídit příkazem ps, který pracuje buďto přímo s pamětí jádra (speciální soubor /dev/kmem) nebo se svazkem /proc. Přitom není definováno žádné volání jádra, které by ps používal. V případě, že jej chtějí jiné procesy napodobit, musí mít přístup k uvedeným systémovým zdrojům, a ty podléhají privilegovanému přístupu. Přestože takovým způsobem lze skutečně PID procesů a jejich atributy získat, proces hledající svůj protějšek komunikace se v těchto informacích může orientovat jen obtížně, protože nemá k dispozici žádný rozumný aparát selekce v seznamu procesů (nehledě na to, že jde o poměrně kostrbatý přístup k informacím). Procesy proto používají signály především v rámci skupiny procesů a při snaze synchronizovat se s procesem mimo tuto skupinu zveřejňují své PID na smluveném místě v systému. Takové místo může být pochopitelně i soubor, ale problémy nastávají s jeho údržbou při nestandardním ukončení procesů nebo celého operačního systému, a proto jsou k výměně PID procesů dnes používány běžně např. i fronty zpráv.
Pro spojení dvou procesů za účelem jednosměrného toku dat byla v původním UNIXu navržena a implementována roura (pipe). Její princip, použití a programování byl uveden v odst. 2.3.3 a v odst. 2.5.1. Přestože jde o elegantní způsob spojení dvou procesů, princip návrhu přináší také několik nevýhod. První je opět v omezení na skupinu procesů. Roura je totiž vytvářena voláním jádra pipe, které obsadí 2 pozice tabulky otevřených souborů procesu. Takto vzniklou rouru dědí každé dítě, a to se může na rouru připojit pro čtení i zápis, stejně jako se na ni může připojit rodič, ale nikdo jiný, protože roura je součástí dědictví, které nelze exportovat do prostředí jiného než dětského procesu. Obecně proto nelze zajistit spojení dvou libovolných procesů. Snaha odstranit tuto nevýhodu vedla k vytvoření tzv. pojmenované roury (named pipe), která je aktivována pomocí otevření souboru (pomocí open), jehož i-uzel má typ roury. Spojení jednosměrného kanálu se jménem souboru tak umožnilo přístup k rouře libovolným procesům. Druhá nevýhoda původní roury je také v její jednosměrnosti. Proces KONZUMENT pouze přijímá data a PRODUCENT je pouze zapisuje. Opačný tok dat není možný, nehledě na vzájemnou synchronizaci toku dat. Implementace obousměrné roury byla řešena pomocí technologie STREAMS na cestě hledání principů implementace síťových protokolů a dnes je možné používat obyčejnou rouru jako obousměrný tok dat. Konečně třetí nevýhoda roury jsou chybějící mechanizmy zajištění struktury přenášených dat, tj. protokolární komunikace. Procesy sice mohou takovou strukturu vytvářet v rámci vlastní interpretace přenášených dat, ale obecně je tok dat rourou, a to pojmenovanou či nepojmenovanou, pouze sekvence bytů.
Původní implementace UNIXu také žádným způsobem neumožňovaly procesům pracovat s pamětí jejich datové oblasti, která by jim byla společná, tzv. sdílená paměť. Procesy mohly data pro sdílení ukládat do souboru, ve kterém se mohly sice efektivně pohybovat pomocí volání jádra lseek, ale tento způsob je zatížen režií systému souborů a pro rychlé výpočty (např. při grafických operacích) se proto nehodí. Navíc původní implementace neřešila zamykání souborů nebo jejich částí. Uvedené nedostatky při používání komunikace procesů pouze pomocí signálů a roury vedly k rozšíření UNIXu o tři další způsoby komunikace, obecně označované zkratkou IPC (Interprocess Communication).
IPC rozšiřuje komunikaci procesů o tři nové způsoby: fronty zpráv (messages), sdílenou paměť (shared memory) a semafory (semaphores). Fronty zpráv využívají procesy pomocí volání jádra msgget, msgsnd, msgrcv a msgctl. Tato komunikace procesů umožňuje pomocí záhlaví zpráv dávat přenášeným datům strukturu a programátor tak získává možnost definovat komunikační protokol. Sdílená paměť je možnost pracovat nad daty společnými několika různým procesům. Mechanizmus volání jádra shmget, shmat, shmdt a shmctl umožňuje sdílenou paměť vytvořit, připojit se k ní a pracovat s ní jako s běžně adresovanou datovou oblastí procesu. Konečně získávat exkluzivní přístup obecně k určitému výpočetnímu zdroji, synchronizovat jeho používání při několikanásobném přístupu různých procesů a zamezovat tak uváznutí v kritických sekcích (deadlock) řeší implementace Dijkstrových semaforů. Proces s nimi manipuluje pomocí volání jádra semget, semop a semctl. Využívání všech tří způsobů komunikace uvedeme v průběhu kapitoly.
IPC znamená obecnou komunikaci více procesů. K tomu, aby se dva libovolné
procesy lokálního operačního systému (různého PID, a to v různých instancích
svého běhu) dokázaly shodnout na identifikaci prostoru, přes který spolu
budou komunikovat, je při vytváření komunikačního prostoru
IPC (tj. fronta zpráv, sdílená paměť nebo semafor) používána celočíselná
identifikace, tzv. klíč IPC. Klíč je používán jednak při vytváření prostoru
komunikace, ale také jej používá každý proces, který se potřebuje na prostor
připojit; jak vytvoření, tak připojení zajišťují volání jádra msgget,
shmget a semget.
Klíč IPC v nich používaný je typu key_t,
má rozsah 32 bitů a používá ji každý proces, který potřebuje s prostorem
pracovat. Přestože rozsah identifikace je příslibem malého procenta kolizí,
kolize se tím samy o sobě neřeší. Kolizí zde rozumíme shodu klíčů dvou
různých komunikací víceprocesových aplikací. Pokud totiž programátor aplikace
použije identifikaci např. 15,
není zaručeno, že operační systém sám tuto identifikaci změní v případě,
že taková již byla použita v jiné skupině procesů (jiné aplikaci). Dochází
ke shodě identifikací a ke kolizi, jejíž důsledky závisí na činnosti jednotlivých
skupin procesů. Pro řešení této situace, tj. jednoznačné stanovení celočíselné
identifikace prostoru komunikace neboli klíče, je v UNIXu používána funkce
ftok (file to key).
Funkce umí na základě jména existujícího souboru vytvořit jedinečný klíč
pro konkrétní instalaci v konkrétním spuštění aplikace. Pokud v téže instalaci
bude spuštěna aplikace jiná a při identifikaci použije jiné jméno souboru
ve funkci ftok, je zajištěno, že
hodnota identifikace prostoru (klíče) bude jiná. Funkce je součástí SVID
(ale ne POSIXu) a má formát
#include <sys/types.h>
#include <sys/ipc.h>
key_t ftok(const char *path, int id);
Jméno souboru na místě path označuje existující soubor. Je to proto, že obvyklá implementace ftok je založena na využití čísla i-uzlu daného souboru (pozor na různá jména téhož i-uzlu, generovaný klíč bude pak tentýž). Pro generaci klíče, který se objeví v návratové hodnotě, ftok dále může používat hlavní a vedlejší číslo sekce disku svazku se souborem path, a tím získá jedinečnou celočíselnou hodnotu v rámci instalace systému. Programátor může dále používat číslování prostorů komunikace v parametru id v případě, že skupina procesů komunikuje více různými způsoby. Uvedené výchozí hodnoty pro výpočet klíče při mechanickém skládání převyšují rozsah 32 bitů (hlavní a vedlejší číslo i-uzlu po 8 bitech, id 16 bitů, samotné číslo i-uzlu 32 bitů), proto je v současných implementacích ignorováno např. hlavní číslo, i-uzel se nepředpokládá vyšší než 16 bitů atd. Důležité je však zajištění výsledku, kdy na základě jména souboru path a číselné identifikace id bude vždy vytvořen jedinečný klíč k označení prostoru komunikace. Při programování je běžný postup, kdy proces, který je odpovědný za vytvoření prostoru komunikace, vytváří soubor path (v případě jeho dřívější existence např. hlásí kolizi) a používá jej pro vytvoření klíče a následně prostoru komunikace IPC. Ostatní procesy pak podle souboru vytvářejí klíč a připojují se. Příklady jsou uvedeny v dalších částech kapitoly.
Jádro registruje všechny aktivity IPC. Uživatel má právo seznámit se s těmi aktivitami, které mu jsou dostupné pro čtení (privilegovaný čte všechny), a to pomocí příkazu ipcs. Příkaz na standardní výstup vypisuje tabulku existujících prostorů komunikace s jejich atributy. Pokud uživatel potřebuje některý prostor odstranit, může používat příkaz ipcrm, má-li potřebná oprávnění. ipcrm používá uvedená volání jádra, ipcs pak obsah tabulek jádra (ve speciálním souboru /dev/kmem nebo informace svazku /proc). Podrobnosti potřebné k používání obou příkazů uvedeme v závěru kapitoly (odst. 4.8).
Při využívání technologií IPC je uplatňována tzv. architektura klient-server
(client-server). Serverem rozumíme automatizovaného správce a poskytovatele
určitého výpočetního zdroje, klientem naopak mechanizmus, který služby
serveru využívá. Pod pojmem architektura klient-server pak rozumíme komunikaci
mezi nimi, která má za cíl klient uspokojit. V pojmech UNIXu a IPC je serverem
proces, který spravuje prostor komunikace (vytváří jej, nastavuje přístupová
práva, naplňuje informacemi, uzavírá a ruší jej atd.). Klient je každý
proces, který se na prostor připojuje a využívá jej ke své další činnosti
(čte nebo zapisuje informace). Použijeme-li jako příklad fronty zpráv,
server bude procesem, který frontu zpráv mimo jiné vytvoří a nakonec zruší.
Klient je každý proces, který frontu zpráv využije pouze pro čtení nebo
zápis zprávy. Použitá volání jádra mají typický charakter podle obr. 4.1.
Z obrázku je patrné, že komunikace se účastní obecně více procesů v roli klientů, ale pouze jeden proces ...