====== 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 } .. }