====== Mezi-procesová komunikace (IPC) ======
* sdílená paměť
* nepojmenovaná roura (pipe)
* pojmenovaná roura
* unix soket
* [[c_network|IP soket]]
* POSIX_Message_Queues
* DBus
===== Sdílená paměť =====
* [[http://advancedlinuxprogramming.com/alp-folder/alp-ch05-ipc.pdf|výborné čtení o meziprocesorové komunikaci, sdílené paměti, semaforech....]]
* POSIX Shared Memory Operations [[http://menehune.opt.wfu.edu/Kokua/More_SGI/007-2478-008/sgi_html/ch03.html#id29423|1]] [[http://www.cs.cf.ac.uk/Dave/C/node27.html#SECTION002740000000000000000|2]]
* mmap(2) - Map a file or shared memory object into the address space.
* shm_open(2) - Create, or gain access to, a shared memory object.
* shm_unlink(2) - Destroy a shared memory object when no references to it remain open.
* http://www3.physnet.uni-hamburg.de/physnet/Tru64-Unix/HTML/APS33DTE/DOCU_004.HTM
* všechny procesy mají přístup do paměti ihned
* začíná se voláním ''shm_open''
* pro přístup do sdílené paměti musí procesy použít stejný name... což je string, například pathname
* System V Shared Memory Functions [[http://menehune.opt.wfu.edu/Kokua/More_SGI/007-2478-008/sgi_html/ch03.html#id17480|1]] [[http://www.cs.cf.ac.uk/Dave/C/node27.html|2]]
* shmget(2) - Create a shared memory IPC object or return the ID of one.
* shmctl(2) - Get the status of a shared memory segment, change permissions or user IDs, or lock or unlock a segment in memory.
* shmat(2) - Attach a shared memory segment to the address space.
* shmdt(2) - Detach a shared memory segment from the address space.
==== Zamykaní ====
* obecně existuje zámek (mutex) nebo semafor (semaphor)
* mutex
* pouze jeden proces/vlakno může vstoupit
* dá se říct, že je to semafor s číslem 1
* slouží k serializaci přístupu
* semafor
* nastaví se počet X, kolik procesů/vláken může max vstoupit
* slouží k omezení paralelního přístupu na max X
Existuje C++ třída mutex
POSIX semafory [[http://linux.die.net/man/7/sem_overview|1]] [[http://menehune.opt.wfu.edu/Kokua/More_SGI/007-2478-008/sgi_html/ch04.html#id82695|2]]
* pojmenované semafory
* identifikuje se jménem se ve tvaru "/řetězec" s max délkou 251
* vytváří se jako soubor v /dev/shm s názvem "sem.řetězec"
* ''sem_open'' - vytváří
* ''sem_close'' - ukončuje práci s
* ''sem_unlink'' - úplně likviduje (poslední proces)
* ''sem_post''
* ''sem_wait''
* nepojmenované semafory
* identifikuje se číslem
* vytváří se v paměti
* jako globální proměnná - mezi vlákny
* ve sdílené paměti - mezi procesy
* ''sem_init'' - vytváří
* ''sem_destroy'' - volat před dealokaci paměti
* ''sem_post''
* ''sem_wait''
System V Semafor [[http://menehune.opt.wfu.edu/Kokua/More_SGI/007-2478-008/sgi_html/ch04.html#id16331|1]]
* oprávnění se nastavuje 9 bitovým číslem (obdoba oprávnění u souboru), tedy například 666
* ''semget'' - alokuje (ve sdílené paměti) nebo získá semafor s daným id
* ''semop'' - provádí operace se smaforem jako init, wait, post nebo i dealokaci
* semafor prý existuje, i když všechny procesy skončí!!!
* lze vypsat přes ipcs -s
===== Nepojmenovaná roura =====
* jednosměrná
* dva konce - producent a konzument
* do roury by měl zapisovat nebo z ní číst pouze jeden proces
* čtení je destruktivní (přečtení jedním procesem zruší možnost čtení procesem druhým)
* zápis/čtení do velikosti 'PIPE_BUF' by mělo být atomické (pokud do roury budou zapisovat dva procesy, tak zápisy do uvedené velikosti by se neměli pomíchat dohromady)
* roura se vytváří příkazem ''pipe''
* parametrem je ''int[2]'', kde index 0 je deskriptor pro zápis a index 1 pro čtení
* rouru je potřeba na konci uzavřít příkazem ''close''
* zapisovat lze příkazem ''write'', číst příkazem ''read''
* při čtení z roury, zavřené na druhé straně, se přečte znak EOF
* při zápisu do roury, zavřené na druhé straně, se generuje signál SIGPIPE (ukončí běh aplikace)
#include
int pipefd[2];
pipe(pipefd);
..
close(pipefd[0]);
close(pipefd[1]);
==== Spojení s procesem jednosměrně ====
* poepen
* pclose
==== Spojení s procesem obousměrně ====
* vytvořit rouru //ipipe// pro jeden směr (rodič -> potomek)
* vytvořit rouru //opipe// pro druhý směr (potomek -> rodič)
* provést fork
* zavřít nepoužívané deskriptory
* v potomkovi zavřít deskriptor pro zápis do //ipipe//
* v potomkovi zavřít deskriptor pro čtení do //opipe//
* v rodiči zavřít deskriptor pro zápis do //opipe//
* v rodiči zavřít deskriptor pro čtení do //ipipe//
* ostatní deskriptory použít pro zpracování
* můžeme z nich číst/zapisovat
* můžeme je použít jako náhradu pro stdin (''STDIN_FILENO''), stderr (''STERR_FILENO'') nebo stdout (''STDOUT_FILENO'')
==== Neblokující roura ====
* standardně je čtení a zápis blokující
* pro neblokující je potřeba změnit nastavení přes syscall ''fcntl'' (pro každý konec roury)
// set non-blocking mode
if (fcntl(pipe_fd, F_SETFL, fcntl(pipe_fd, F_GETFL) | O_NONBLOCK) == -1) {
fprintf(stderr,"Cannot set non-blocking mode to pipe\n");
}
// set blocking mode
if (fcntl(pipe_fd, F_SETFL, fcntl(pipe_fd, F_GETFL) & ~O_NONBLOCK) == -1) {
fprintf(stderr,"Cannot set blocking mode to pipe\n");
}
* chování funkcí read a write se v non-blocking režimu mění
* pokud nejsou žádná data ke čtení, ale roura je pořád otevřena, vrátí funkce read chybovou návratovou hodnotu (-1) a ''errno'' nastaví na ''EAGAIN''
* pro ověření, zda jsou data připravena pro zápis/čtení je vhodné používat nějakou funkci, například ''select''
struct timeval tv;
fd_set rfds;
fd_set wfds;
int nfds;
// set highest pipe FD +1
nfds = (pipefd[0]>pipefd[1])?pipefd[0]+1:pipefd[1]+1;
while(...) {
FD_ZERO(&rfds);
FD_SET(pipefd[0],&rfds);
FD_ZERO(&wfds);
FD_SET(pipefd[1],&wfds);
tv.tv_sec = 5;
tv.tv_usec = 0;
if (select(nfds, &rfds, &wfds, NULL, &tv) == -1) {
fprintf(stderr,"pipe error %d\n", errno);
}
if (FD_ISSET(pipefd[0], &rfds)) {
..
// do reading
}
..
}