7. System V IPC
Sisältö:
7 System V IPC
#include < sys/ipc.h > #include < sys/shm.h > Yhteiskäyttöinen muisti #include < sys/sem.h > Semaforit #include < sys/msg.h > Sanomanvälitys
Perustuvat prosessien yhteiskäytössä olevaan muistiin prosessien pyörittävä samassa koneessa. Prosessien ei tarvitse olla 'sukua', vaan käyttöoikeudet määräytyvät tiedostojen tyyliin (u, g, o). Yhteiskäytön tunnisteena yksikäsitteiset positiiviset avaimet (key_t key). Siis asiakkaan ja palvelijan tunnettava yht. avain Avainten nimiavaruudet erillisiä muistialueille, semaforijoukoille ja sanomajonoille. avain (key) on 32 bittinen pysyvin nimi, oikeastaan vakio. Unix näyttää heksalukuna. Tunnus (id) on 32 bittinen muuttuja, jonka arvo riippuu ilmentymästä ('ajokerrasta'). 'Kahva', jonka kautta päästään käsiksi käsiteltävään asiaan. Osoite (address) on muuttuja. Olemassa vain muistialueille. KJ asettaa, kun alue kuvataan prosessin muistiin. Miten asiakas ja palvelija sopivat avaimen?
- Avain sovittu, esim. yhteisessä otsaketiedostossa (yhteentörmäysvaara)
- Palvelija käyttää luodessa avainta IPC_PRIVATE toimittaa sen asiakkaalle tiedostossa, putkessa. Oma lapsi perii avaimen forkissa asiakkaalle komentoriviargumenttina
- Sovittu polkunimi ja lisäliite (esim. projektinumero), jotka muutetaan avaimeksi kutsulla ftok().
Avaimen voi luoda tiedostonimestä funktiolla key_t ftok(char *path, char id);, jossa path on jonkin olemassaolevan tiedoston polkunimi ja id on sovittu lisäliite. Ytimen ylläpitämät yhteiskäyttöön liittyvät rakenteet voivat jäädä olemaan vaikka prosessi päättyykin.
IPC-rakenteet eivät näy esim. ls-komennon tulosteissa, kuten esim. putket ja pistokkeet (käyttävät tiedostokuvaajia). Miten poistetaan 'roikkumaan' jääneet IPC-rakenteet? Katso komennot ipcs(1) ja ipcrm(1).
Select() ja poll() eivät ole käytettävissä, joten on vaikea järjestellä kommunikointi s.e. käytetään esim. useita sanomajonoja. On myös vaikeaa käyttää yhdessä tiedostokuvaajiin perustuvien menetelmien kanssa vaan joudutaan käyttämään aktiivista odotusta ('busy wait').
7.1 Yhteiskäytössä oleva muisti (shared memory)
Nopein prosessien välinen kommunikointitapa, joten sopii samassa koneessa pyöriviin asiakas-palvelin ratkaisuihin. Tarvitaan synkronointia ja poissulkemista. Eli semaforit, tiedostolukot tai signaalit (jos samaa prosessiperhettä). Systeemikutsuja lähinnä vain käsittelyä aloitettaessa, muuten yhteiskäytössä olevan muistin käyttö ei eroa prosessin data-alueen käytöstä.
shmget(): - luo yhteiskäyttöinen alue, nimeä avain - haku avaimen perusteella shmctl(): - parametritietojen käsittely shmat(): - liitä alue (attach) omaan osoiteavaruuteen shmdt(): - muistialueen vapauttaminen (detach) omasta osoiteavaruudesta Ydin ylläpitää yhteiskäyttöisestä muistista rakennetta struct shmid_ds { struct ipc_perm shm_perm; ks. alla struct anon_map *shm_amp; vie ytimeen int shm_segsz; koko tavuina ushort shm_lkcnt; lukitsemiskertojen lkm pid_t shm_lpid; viim. shmop pid_t shm_cpid; luojan pid ulong shm_nattch; shmat kertojen lkm ulong shm_cnattch; shminfo käyttää tätä time_t shm_atime; viim. attach aika time_t shm_dtime; viim. detach aika time_t shm_ctime; viim. muutos aika }; Käyttöoikeudet on kirjattu tiedostojen tapaan: struct ipc_perm { uid_t uid; omistajan tunnisteet gid_t gid; uid_t cuid; luojan (creator) tunnisteet gid_t cgid; mode_t mode; käyttöoikeudet ulong seq; käytön järjestysnumero key_t key; }; #include < sys/types.h > #include < sys/ipc.h > #include < sys/shm.h > int shmget(key_t key, int size, int flag); palauttaa: jaetun alueen SHMID shmget() etsii tai luo muistialueen, jonka avain on annettu. Tarkistaa käyttöoikeudet. Jos luo alueen, alustaa käyttöoikeudet (rakenne ipc_perms) key: alueen tunniste (yksikäs. kokonaisluku) IPC_PRIVATE size: varattavan alueen minimikoko 0, jos olemassaolevan alueen haku flag: käyttöoikeudet IPC_CREAT IPC_EXCL IPC_NOWAIT
Ko. alueeseen viitataan käytettäessä funktion shmget() palauttamalla id:llä.
#include < sys/types.h > #include < sys/ipc.h > #include < sys/shm.h > void *shmat(int shmid, void *addr, int flag); palauttaa: osoitin jaetun alueen alkuun shmat() liittää (attach) yhteiskäytössä olevan alueen prosessin virtuaaliavaruuteen. palauttaa osoittimen alueen alkuun. shmid: alueen tunniste addr: addr == 0 ydin saa valita paikan addr !=0 annettuun osoitteeseen addr !=0, flag == shm_rnd osoitteeseen (addr - (addr mod shmlba)) lba: "low boundary address multiple" flag: shm_rnd shm_rdonly suositus: käytä addr = 0
#include < sys/types.h > #include < sys/ipc.h > #include < sys/shm.h > int shmctl(int shmid, int cmd, struct scmid_ds *buf); shmctl() kysyy tai asettaa yhteiskäytössä olevan alueen parametritietoja. cmd: ipc_stat nouda scmid_ds rakenteen tiedot ipc_set aseta shm_perm.uid, shm_perm.gid, shm_perm.mode ipc_rmid poista alue omasta muistista shm_lock lukitse yhteiskäytössä oleva alue muistiin (sallittua vain root) shm_unlock vapauta lukitus (vain root)
alueen poisto muistista on sallittu vain sen luojalle. muut saavat paluuarvon -1 ja errno == eidrm. alue jää muiden senhetkisten käyttäjien käyttöön. se poistuu lopullisesti muistista, kun kaikki shmat()- kutsut on 'kumottu' kaikissa prosesseissa. vaarana 'roskien' jääminen muistiin yhteiskäytössä oleva muisti ei säily exec()-kutsussa.
#include < sys/types.h > #include < sys/ipc.h > #include < sys/shm.h > int shmdt(void *addr); shmat() vapauttaa (detach) yhteiskäytössä olevan alue prosessin virtuaaliavaruudesta. alue jää silti muistiin muiden käytettäväksi! addr: osoite, joka saatiin shmat()-kutsussa
7.2 Semaforit
Semafori on 'erityistä suojelua' nauttiva ei- negatiivinen kokonaisluku, jolla on alkuarvo (yl. jaossa olevien resurssien määrä) ja johon liittyy odotusjono. tarkoitettu yhteiskäytössä olevien resurssien käyttövuorojen hallintaan eli synkronointiin ja poissulkemiseen.Prosessi voi kasvattaa semaforin arvoa milloin vain, mutta vähentää arvoa, vain jos arvo > 0, muuten prosessi odottaa kunnes vähennys on mahdollista.
Odotus päättyy, kun toinen prosessi kasvattaa semaforin arvoa. odotuksen jälkeen on semaforin arvoa tutkittava aina uudelleen, sillä odottaneista prosesseista vain joku / jotkut pääsevät jatkamaan. semaforioperaatio aloitetaan alusta uudelleen. atominen operaatio, saadaan kaikki mitä pyydetään tai sitten ei mitään. systeemikutsut:
- semget():
- luo semaforijoukko ja nimeä avain
- etsi semaforijoukko avaimen perusteella
- semctl():
- aseta semaforiin liittyviä parametreja
- semaforien vapautus muistista
- semop():
- tee semaforiin liittyviä operaatioita
- kasvatus, vähennysydin ylläpitää jokaisesta joukosta tietorakennetta:
struct semid_ds { struct ipc_perm sem_perm; oikeudet struct sem *sem_base; osoitin ens. ushort sem_nsems; lukumäärä time_t sem_otime; milloin viim. semop time_t sem_ctime; milloin viim.muutettu }; struct sem { ushort semval; semaforin arvo pid_t sempid; kuka käytti viimeeksi ushort semncntl; odott. lkm, että arvo kasvaisi ushort semzcntl; odott. lkm, että arvo 0 };
#include < sys/types.h > #include < sys/ipc.h > #include < sys/sem.h > int semget(key_t key, int nsems, int flag); palauttaa: semid semget() etsii tai luo semaforijoukon. alustaa luotaessa rakenteen semid_ds . key: joukon tunniste (yksikäs. kokonaisluku) ipc_private nsems: semaforien lukumäärä semaforijoukossa 0, jos joukko jo olemassa flag: käyttöoikeudet ipc_creat ipc_excl
#include < sys/types.h > #include < sys/ipc.h > #include < sys/sem.h > int semop(int semid, struct sembuf semoparray[], size_t nops);
argumenttina taulukko, jossa voi antaa kerralla useita semaforioperaatioita. atominen: joko tekee kaikki kutsussa annetut operaatiot, tai sitten mitään.
struct sembuf { ushort sem_num; semaforin numero short sem_op; operaatio short sem_flg; ipc_nowait,sem_undo }; sem_op > 0: vapautettavien resurssien lkm semval = semval + sem_op sem_op < 0: varattavien resurssien lkm jos semval >= sem_op niin semval = semval - sem_op muuten jos sem_flag == ipc_nowait niin errno = eagain muuten semncnt = semncnt + 1 odota, että voi varata sem_op == 0: jos semval == 0 niin return jos semval > 0 ja sem_flg == ipc_nowait errno = eagain muuten semzcnt = semzcnt + 1 odota, että semval 0 odotus katkeaa jos joku poistaa semaforijoukon errno = idrm jos prosessi saa signaalin semzcnt = semzcnt - 1 tai semncnt = semncnt - 1 errno = eintr
Jos sem_flg == sem_undo, niin ydin pitää kirjaa prosessin tekemistä varauksista, ja huolehtii niiden vapauttamisesta virhetilanteissa, ts. jos prosessi ei ole vapauttanut, tai jos prosessi kaatuu. undo-lista sopii poissulkemiseen ja muuhun resurssien jakeluun / laskemiseen.
Resurssi ei jää lukkoon vaikka prosessi kuolee kesken sen käsittelyn ei kuitenkaan takaa, että resurssi olisi tämän jälkeen eheässä tilassa (prosessilta saattoi jäädä joku päivitys kesken)
undo-lista ei sovi prosessien väliseen kommunikointiin, koska sama prosessi voi vapauttaa jatkuvasti, joten undo- laskuri vuotaa yli. kuolleen prosessin vastaanottamat sanoamt eivät 'synny uudestaan', vaan ne on pysyvästi kulutettu.
#include < sys/types.h > #include < sys/ipc.h > #include < sys/sem.h > int semctl(int semid, int semnum, int cmd, union semun arg); palauttaa: vaihtelee cmd perusteella semctl() noutaa / asettaa semaforijoukon parametreja. ipc_stat nouda rakenne semid_ds (arg.buf) ipc_set aseta sem_perm.uid, sem_perm.gid,sem_perm.mode ipc_rmid poista semaforijoukko kokonaan muistista getval palauta semaforin semval arvo setval aseta semaforin arvoksi arg.val (alustus) getpid palauta semaforin sempid-kenttä getncnt palauta semaforin semncnt-kenttä getzcnt palauta semaforin semzcnt-kenttä getall nouda kaikkien semaforien arvot taulukkoon arg.array setall aseta kaikkien semaforien arvot taulukosta arg.array union semun { int val; struct semid_ds *buf; ushort *array; };
Esimerkki (sema.c):
#include < stdio.h > #include < sys/types.h > #include < sys/ipc.h > #include < sys/sem.h > #include < sys/shm.h > #include < stdlib.h > #include < errno.h > #include < string.h > int semheld = 0; void release(int id); void request(int id); int main(int argc, char *argv[]) { int id; union semun sunion; /* No arguments: "server". */ if (argc < 2) { /* Request a semaphore. */ id = semget(IPC_PRIVATE, 1, SHM_R | SHM_W); /* Initialize its resource count to 1. */ sunion.val = 1; semctl(id, 0, SETVAL, sunion); } else { /* Open up the existing one. */ id = atoi(argv[1]); printf("Using existing semaphore %d.\n", id); } if (id == -1) { printf("Semaphore request failed: %s.\n", strerror(errno)); return 0; } printf("Successfully allocated semaphore id %d\n", id); while (1) { int selection; printf("\nStatus: %d resources held by this process.\n", semheld); printf("Menu:\n"); printf("1. Release a resource\n"); printf("2. Request a resource\n"); printf("3. Exit this process\n"); printf("Your choice: "); scanf("%d", &selection); switch(selection) { case 1: release(id); break; case 2: request(id); break; case 3: exit(0); break; } } return 0; } void release(int id) { struct sembuf sb; if (semheld < 1) { printf("I don't have any resources; nothing to release.\n"); return; } sb.sem_num = 0; sb.sem_op = 1; sb.sem_flg = 0; semop(id, &sb, 1); semheld--; printf("Resource released.\n"); } void request(int id) { struct sembuf sb; if (semheld > 0) { printf("I already hold the resource; not requesting another one.\n"); return; } sb.sem_num = 0; sb.sem_op = -1; sb.sem_flg = 0; printf("Requesting resource..."); fflush(stdout); semop(id, &sb, 1); semheld++; printf(" done.\n"); }
Toinen esimerkki, jossa käytetään myös jaettua muistia (sema2.c):
#include < stdio.h > #include < sys/types.h > #include < sys/ipc.h > #include < sys/sem.h > #include < sys/shm.h > #include < stdlib.h > #include < errno.h > #include < string.h > #include < signal.h > #include < stdarg.h > union semun { int val; /* value for SETVAL */ struct semid_ds *buf; /* buffer for IPC_STAT, IPC_SET */ unsigned short int *array; /* array for GETALL, SETALL */ struct seminfo *__buf; /* buffer for IPC_INFO */ }; #define SHMDATASIZE 1000 #define BUFFERSIZE (SHMDATASIZE - sizeof(int)) #define SN_EMPTY 0 #define SN_FULL 1 int DeleteSemid = 0; void server(void); void client(int shmid); void delete(void); void sigdelete(int signum); void locksem(int semid, int semnum); void unlocksem(int semid, int semnum); void waitzero(int semid, int semnum); void clientwrite(int shmid, int semid, char *buffer); int safesemget(key_t key, int nsems, int semflg); int safesemctl(int semid, int semnum, int cmd, union semun arg); int safesemop(int semid, struct sembuf *sops, unsigned nsops); int safeshmget(key_t key, int size, int shmflg); void *safeshmat(int shmid, const void *shmaddr, int shmflg); int safeshmctl(int shmid, int cmd, struct shmid_ds *buf); void HandleError(int ecode, const char *const caller, const char *fmt, ...); int main(int argc, char *argv[]) { /* No arguments: "server". */ if (argc < 2) { server(); } else { client(atoi(argv[1])); } return 0; } void server(void) { union semun sunion; int semid, shmid; void *shmdata; char *buffer; /* First thing: generate the semaphore. */ semid = safesemget(IPC_PRIVATE, 2, SHM_R | SHM_W); DeleteSemid = semid; /* Delete the semaphore when exiting. */ atexit(&delete); signal(SIGINT, &sigdelete); /* Initially empty should be available and full should not be. */ sunion.val = 1; safesemctl(semid, SN_EMPTY, SETVAL, sunion); sunion.val = 0; safesemctl(semid, SN_FULL, SETVAL, sunion); /* Now allocate a shared memory segment. */ shmid = safeshmget(IPC_PRIVATE, SHMDATASIZE, IPC_CREAT | SHM_R | SHM_W); /* Map it into memory. */ shmdata = safeshmat(shmid, 0, 0); /* Mark it to automatically delete when the last holding process exits. */ safeshmctl(shmid, IPC_RMID, NULL); /* Write the semaphore id to its beginning. */ *(int *)shmdata = semid; buffer = shmdata + sizeof(int); printf("Server is running with SHM id ** %d **\n", shmid); /***************************************************************** MAIN SERVER LOOP *****************************************************************/ while (1) { printf("Waiting until full..."); fflush(stdout); locksem(semid, SN_FULL); printf(" done.\n"); printf("Message received: %s\n", buffer); unlocksem(semid, SN_EMPTY); } } void client(int shmid) { int semid; void *shmdata; char *buffer; shmdata = safeshmat(shmid, 0, 0); semid = *(int *)shmdata; buffer = shmdata + sizeof(int); printf("Client operational: shm id is %d, sem id is %d\n", shmid, semid); while (1) { char input[3]; printf("\n\nMenu\n1. Send a message\n"); printf("2. Exit\n"); fgets(input, sizeof(input), stdin); switch(input[0]) { case '1': clientwrite(shmid, semid, buffer); break; case '2': exit(0); break; } } } void delete(void) { printf("\nMaster exiting; deleting semaphore %d.\n", DeleteSemid); if (semctl(DeleteSemid, 0, IPC_RMID, 0) == -1) { printf("Error releasing semaphore.\n"); } } void sigdelete(int signum) { /* Calling exit will conveniently trigger the normal delete item. */ exit(0); } void locksem(int semid, int semnum) { struct sembuf sb; sb.sem_num = semnum; sb.sem_op = -1; sb.sem_flg = SEM_UNDO; safesemop(semid, &sb, 1); } void unlocksem(int semid, int semnum) { struct sembuf sb; sb.sem_num = semnum; sb.sem_op = 1; sb.sem_flg = SEM_UNDO; safesemop(semid, &sb, 1); } void waitzero(int semid, int semnum) { struct sembuf sb; sb.sem_num = semnum; sb.sem_op = 0; sb.sem_flg = 0; /* No modification so no need to undo */ safesemop(semid, &sb, 1); } void clientwrite(int shmid, int semid, char *buffer) { printf("Waiting until empty..."); fflush(stdout); locksem(semid, SN_EMPTY); printf(" done.\n"); printf("Enter message: "); fgets(buffer, BUFFERSIZE, stdin); unlocksem(semid, SN_FULL); } int safesemget(key_t key, int nsems, int semflg) { int retval; retval = semget(key, nsems, semflg); if (retval == -1) HandleError(errno, "semget", "key %d, nsems %d failed", key, nsems); return retval; } int safesemctl(int semid, int semnum, int cmd, union semun arg) { int retval; retval = semctl(semid, semnum, cmd, arg); if (retval == -1) HandleError(errno, "semctl", "semid %d, semnum %d, cmd %d failed", semid, semnum, cmd); return retval; } int safesemop(int semid, struct sembuf *sops, unsigned nsops) { int retval; retval = semop(semid, sops, nsops); if (retval == -1) HandleError(errno, "semop", "semid %d (%d operations) failed", semid, nsops); return retval; } int safeshmget(key_t key, int size, int shmflg) { int retval; retval = shmget(key, size, shmflg); if (retval == -1) HandleError(errno, "shmget", "key %d, size %d failed", key, size); return retval; } void *safeshmat(int shmid, const void *shmaddr, int shmflg) { void *retval; retval = shmat(shmid, shmaddr, shmflg); if (retval == (void *) -1) HandleError(errno, "shmat", "shmid %d failed", shmid); return retval; } int safeshmctl(int shmid, int cmd, struct shmid_ds *buf) { int retval; retval = shmctl(shmid, cmd, buf); if (retval == -1) HandleError(errno, "shmctl", "shmid %d, cmd %d failed", shmid, cmd); return retval; } void HandleError(int ecode, const char *const caller, const char *fmt, ...) { va_list fmtargs; struct sigaction sastruct; /* Print the error message(s) */ va_start(fmtargs, fmt); fprintf(stderr, "*** Error in %s: ", caller); vfprintf(stderr, fmt, fmtargs); va_end(fmtargs); fprintf(stderr, "\n"); if (ecode) { fprintf(stderr, "*** Error cause: %s\n", strerror(ecode)); } /* Exit if no signal handler. Otherwise, raise a signal. */ sigaction(SIGUSR1, NULL, &sastruct); if (sastruct.sa_handler != SIG_DFL) { raise(SIGUSR1); } else { exit(254); } }
7.4 Perinteinen p ja v
Oerinteisesti semafori-operaatioista on käytetty tunnuksia p() ja v():
p(sem) jos sem == 0 niin jää odottamaan muuten sem = sem - 1 v(sem) sem = sem + 1 herätä odottajat sysv:n mekanismi sallii myös p(sem,n) jos sem > n niin sem = sem - n muuten jää odottamaan v(sem,n) sem = sem - n z(sem) odota, kunnes sem = 0
tuottaja do tuota data p(tyhja) p(mutex) vie puskuriin v(mutex) v(täysi) while (1); kuluttaja do p(täysi) p(mutex) ota puskurista v(mutex) v(tyhja) kuluta data while (1);
Edelliseen ratkaisuun saa helposti lukkiutuman, kun vaihtaa kummassa tahansa kahden ensimmäisen p()- operaation paikkaa keskenään. yleisiä ratkaisuja:
- järjestyskuri: varaukset kaikissa prosesseissa samassa järjestyksessä (vrt. tilinumerot)
- jos ei saa varattua lisäresurssia, vapautetaan aiemmin varatut resurssit
- operaatiot voi määritellä funktiossa semop() semaforijoukolle. se ei varaa mitään, ellei saa kaikkia varauksia tehtyä.
7.5 Sanomanvälitys
Sanoma muodostuu: sanoman tyypistä, pituuskentästä ja sanoman tavuista. sanomia ei tarvitse käsitellä niiden välitysjärjestyksessä, voi noutaa myös tyypin perusteella (esim. prioriteetti). systeemikutsut:
- sgget():
- luo sanomajono ja nimeä avain
- etsi sanomajono avaimen perusteella
- msgsnd():
- vie sanoma sanomajonoon
- msgrcv():
- hae sanoma sanomajonosta
- msgctl():
- aseta sanomajonoon liittyviä parametreja
- sanomajonoin vapautus muististaJokaiselle sanomajonolle on tietorakenne
struct msqid_ds { struct ipc_perm shm_perm; struct msg_first; osoitin jonon ensimm. struct msg_last; osoitin jonon viimeiseen ulong msg_cbytes; tavujen lkm jonossa ulong msg_qnum; sanomien lkm jonossa ulong msg_qbytes; tavujen max lkm pid_t msg_lspid; viim. msgsnd pid pid_t msg_lrpid; viim. msgrvc pid time_t msg_atime; viim. msgsnd aika time_t msg_dtime; viim. msgrcv aika time_t msg_ctime; viim. muutos aika }; #include < sys/ipc.h > #include < sys/msg.h > int msgget(key_t key, int flag); palauttaa: sanomajonon tunniste MSQID
msgget() etsii tai luo sanomajonon. Alustaa luotaessa rakenne msqid_ds.
key: sanoman tunniste (yksikäs. kokonaisluku) IPC_PRIVATE flag: käyttöoikeudet IPC_CREAT IPC_EXCL
Funktion palauttaamaa arvoa MSQID käytetään kahvana muissa kutsuissa.
#include < sys/types.h > #include < sys/ipc.h > #include < sys/msg.h > int msgctl(int msqid, int cmd, struct msqid_ds *buf);
msgctl() noutaa tai asettaa sanomajonon parametritietoja.
IPC_STAT Nouda msqid_ds rakenteen tiedot IPC_SET Aseta msg_perm.uid, msg_perm.gid, msg_perm.mode, msg_qbytes IPC_RMID Poista sanomajono kokonaan muistista
Vain sanomajonon luoja saa käyttää komentoa IPC_RMID, muut saavat errno == EIDRM.
#include < sys/types.h > #include < sys/ipc.h > #include < sys/msg.h > int msgsnd(int msqid, const void *ptr, size_t nbytes, int flag); msgsnd() vie sanoman jonoon. ptr: osoitin alueeseen, jossa tyyppi ja sanoman tavut, esimerkiksi struct mymesg { long mtype; tyyppi (sovi itse) char mtext[512]; data (max pituus) }; nbytes: dataosan todellinen pituus jos jono täynnä ja flag == IPC_NOWAIT niin errno = EAGAIN muuten odota, että sanomalle on tilaa jos joku poistaa sanomajonon, niin errno = ERMID jos prosessi saa signaalin, niin errno = EINTR
#include < sys/types.h > #include < sys/ipc.h > #include < sys/msg.h > int msgrcv(int msqid, void *ptr, size_t nbytes,long type, int flag); palauttaa: montako tavua saatiin msgrcv() hakee sanoman jonosta. ptr: kuten msgsnd() nbytes: montako tavua maksimissaan type = 0: palauta jonon ensimmäinen type > 0: palauta ens., jonka tyyppi == type type < 0: palauta pienin sanoma., jonka type <= abs(type) jos jono on tyhjä ja flag == IPC_NOWAIT errno = ENOMSG muuten odota, kunnes oikean tyyppinen haettavissa jos joku poistaa sanomajonon, niin errno = EIDRM jos prosessi saa signaalin, niin errno = EINTR
Esimerkki vastaanottajasta (Esim1).
#include < sys/types.h > /* Receive */ #include < sys/ipc.h > #include < sys/msg.h > #include < stdio.h > #include < stdlib.h > #include < fcntl.h > #include < errno.h > int main(int argc, char *argv[]) /* argumenttina: tiedostonimi */ { key_t key; int id; long type; typedef struct { long mtype; char mtext[1]; } msg_t; size_t msize; /* paljonko tilaa varattu */ msg_t *mess; int mlen; /* todellinen pituus */ if ((key = ftok(argv[1],'D')) == -1) perror("msgrcv: ftok"); if ((id = msgget(key, IPC_CREAT|0777))== -1) perror("msgrcv: msgget"); /* varaa tilaa sanomalle */ msize = 20; if ((mess = (msg_t *)malloc(sizeof(long) + msize + 1)) == NULL) perror("msgrcv: malloc"); /* ota vastaan sanomia */ do { if ((mlen=msgrcv(id, mess, msize, getpid(), 0)) == -1) { if (errno == EINTR) continue; if (errno == E2BIG) { free(mess); msize *= 2; printf("%d sanoman koko -> %d\n", getpid(), msize); if ((mess = (msg_t *)malloc(sizeof(long)+msize+1)) == NULL) perror("msgrcv: malloc"); continue; } perror("msgrcv: msgrcv"); } mess->mtext[mlen] = (char) 0;; printf("%d '%s'\n", getpid(), mess->mtext); } while (mlen != 0); free(mess); exit(0); }Esimerkki lähettäjästä (Esim2).
#include < sys/types.h > /* Send */ #include < sys/ipc.h > #include < sys/msg.h > #include < stdio.h > #include < stdlib.h > int main(int argc, char *argv[]) /* argumentteina saadaan: tiedostonimi, tyyppi, teksti */ { key_t key; int id; long type; typedef struct { long mtype; char mtext[1]; } msg_t; size_t mlen; msg_t *mess; /* etsi sanomajono */ if ((key = ftok(argv[1],'D')) == -1) perror("msgsnd: ftok"); if ((id = msgget(key,0)) == -1) perror("msgsnd: nsgget"); /* kokoa sanoma */ if ((type = atol(argv[2])) <= 0) perror("msgsnd: tyyppi ei voi olla < 0"); mlen = strlen(argv[3]); if ((mess = (msg_t *) malloc(sizeof(long) + mlen)) == NULL) perror("msgsnd: malloc"); mess->mtype = type; memcpy(mess->mtext, argv[3], mlen); /* lähetä sanoma */ if (msgsnd(id, mess, mlen, 0) != 0) perror("msgsnd: msgsnd"); free(mess); exit(0); }
Jan Lindström (Jan.Lindstrom@cs.Helsinki.FI)