Νσίπληρ Νίκορ- ΕΣΤ 4ο ΥΡΟΝΣΙΣΗΡΙΟ Παπαςκετή 4-11-2013 Β4 1
Κοινή Μνήμη μεσαξύ διεπγαςιών -> Γπηγοπόσεπη μοπυή IPC Σα δεδομένα δεν ανσιγπάυονσαι πάνω από μία υοπά Server/Client model. Όσαν ο Server γπάυει, ο client ππέπει να διαβάςει όσαν ο server έφει σελειώςει. Φπειάζεσαι ςτγφπονιςμόρ Φπήςη semaphors - 2 -
Δημιοτπγία κοινήρ μνήμηρ από διεπγαςία shmget() Πποςκόλληςη διεπγαςίαρ ςσηρ κοινή μνήμη shmat() Αποκόλληςη διεπγαςία; από κοινή μνήμη shmdt() Έλεγφορ κοινήρ μνήμηρ (πεπιλαμβάνει διαγπαυή) shmctl() man (shmget) man(shmat) man(shmdt) man(shmctl) - 3 -
Με σην shmget() παίπνοτμε ένα shared memory identifier #include<sys/types.h> #include<sys/ipc.h> #include<sys/shm.h> int shmget(key_t key, int size, int flag); Η shmget() επιςσπέυει ένα shared memory ID if OK και -1 αν error Σο «key» είναι ςτνήθωρ η ςσαθεπά IPC_PRIVATE, ποτ ζησά από σον kernel έναν non-negative integer identifier ποτ η σιμή σοτ ατξάνει μέφπι μια μέγιςση σιμή ππιν μηδενιςσεί. Σο «size» είναι σο μέγεθορ σων shared memory segment ςε bytes Σο «flag» μποπεί να είναι SHM_R, SHM_W ή SHM_R SHM_W - 4 -
Όσαν ένα shared memory segment έφει δημιοτπγηθεί, σο process σο κάνει attach ςσο address space σοτ καλώνσαρ σην shmat(): void *shmat(int shmid, void* addr, int flag); Η shmat() επιςσπέυει έναν pointer ςε ένα shared memory segment αν OK και -1 αν error Η ςτνήθηρ πποσεινόμενη ππογπαμμασιςσική σεφνική είναι να θέσονσαι σο addr και flag ςσο μηδέν, πφ: char* buf = (char*)shmat(shmid,0,0); σο UNIX οι ενσολέρ ipcs και ipcrm φπηςιμοποιούνσαι για να κάνοτν list και remove shared memory segments ςσο current machine. Σο default action για ένα shared memory segment είναι να παπαμένει ςσο ςύςσημα ακόμα και μεσά σο θάνασο μιαρ διεπγαςίαρ. Αν θέλοτμε να σο απουύγοτμε ατσό (και ςτνήθωρ σο θέλοτμε!) φπηςιμοποιούμε σην shmctl(). - 5 -
Η shmctl() κάνει απκεσά ππαγμασάκια: int shmctl (int shmid, int cmd, struct shmid_ds *buf); Σο «cmd» μποπεί να είναι ένα από σα IPC_STAT, IPC_SET, ή IPC_RMID. Μποπούμε εύκολα να δούμε σι κάνει σο καθένα από ατσά. Με ένα googlάπιςμα βπίςκοτμε: IPC_STAT fills the buf data structure IPC_SET can change the uid, gid, and mode of the shmid IPC_RMID sets up the shared memory segment to be removed from the system once the last process using the segment terminates or detaches from it a process detaches from a shared memory segment using shmdt(void* addr), which is similar to free() Η shmctl() επιςσπέυει 0 αν OK και -1 αν error - 6 -
shm_id = shmget(shm_key, SHM_SIZE, 0600); if (shm_id < 0) { printf("could not create shared memory!\n"); exit(1); } data = shmat(shm_id, NULL, 0); //δείκτης προς την αρχή της sm if (data == (char *)-1) { printf( Could not attach to shared memory!\n ); exit(1); } - 7 -
char* ShareMalloc(int size) { int shmid; char* returnptr; if ((shmid=shmget(ipc_private, size, (SHM_R SHM_W)) < 0) Abort( Failure on shmget\n ); if (returnptr=(char*)shmat(shmid,0,0)) == (void*) -1) Abort( Failure on shmat\n ); shmctl(shmid, IPC_RMID, (struct shmid_ds *) NULL); return (returnptr); } - 8 -
Σι θα ςτμβεί αν σπέξοτμε σο παπακάσω κομμάσι κώδικα; int main(void) { pid_t pid; if ((pid = fork()) < 0) Abort( Fork Error ); else if (pid == 0) charatatime( output from child\n ); else charatatime( output from parent\n ); exit(0); } Έφοτμε σο υαινόμενο σοτ «compile time non-determinism»! Διαδοφικά run σοτ παπαπάνω κώδικα δίνοτν και διαυοπεσικά αποσελέςμασα! - 9 -
Αν θέλοτμε να επέμβοτμε ςση ςειπά εκσέλεςηρ (γιασί για παπάδειγμα η διεπγαςία-γονιόρ φπειάζεσαι κάποια δεδομένα από ση διεπγαςία παιδί) μποπούμε να κάνοτμε wait. ε ατσή σην πεπίπσωςη φπηςιμοποιούμε signals. Διαυοπεσικά κάνοτμε busy waiting κοισώνσαρ ένα flag, κάσι όμωρ ποτ υτςικά θέλοτμε να σο απουεύγοτμε! Όμωρ για θτμηθείσε σο παπάδειγμα σων Υιλοςόυων! Φπειαζόμαςσε και έναν «διαισησή» (ή έναν «ςεπβισόπο» ςσην πεπίπσωςη σων υιλοςόυων). Ατσόρ είναι ο πόλορ σοτ semaphor - 10 -
Code that modifies shared data usually has the following parts: Entry section: The code that requests permission to modify the shared data. Critical Section: The code that modifies the shared variable. Exit Section: The code that releases access to the shared data. Remainder: The remaining code The critical section problem refers to the problem of executing critical sections in a fair, symmetric manner. Solutions to the critical section problem must satisfy each of the following: Mutual Exclusion: At most one process is in its critical section at any time Progress: If no process is executing its critical section, a process that wishes to enter can get in Bounded Waiting: No process is postponed indefinitely An atomic operation is an operation that, once started, completes in a logical indivisible (=αδιαίπεσορ) way. Most solutions to the critical section problem rely on the existence of certain atomic operations - 11 -
Έναρ semaphore είναι μια ακέπαια μεσαβλησή με δύο atomic operations: wait and signal. Άλλερ ονομαςίερ ποτ θα βπείσε για ατσέρ είναι down, P και lock για σο wait και up, V, unlock και post για σο signal. Μία process ποτ κάνει wait ςε έναν semaphore S δεν μποπεί να ςτνεφίςει μέφπι η σιμή σοτ S είναι θεσική. Μεσά μειώνει κασά ένα σην σιμή σοτ is S. Όσαν γίνει «signal» η σιμή σοτ S μεγαλώνει κασά ένα. Σι δεν θέλοτμε να κάνει έναρ semaphor; void wait(int *s) { while (*s <= 0); /* END WHILE*/ (*s)--; } void signal(int *s) { (*s)++; } - 12 -
Σο ππόβλημα με σον κώδικα ατσό είναι απφικά σο busy waiting και επίςηρ σο γεγονόρ όσι οι ππάξειρ «- -» και «+ +» δεν είναι atomic! Ατσό ποτ θέλοτμε να κάνοτμε είναι σο ακόλοτθο: wait(&s); /* critical section */ signal(&s); /* remainder section */ και ατσό γίνεσαι με ση φπήςη σων system calls semget() και semop() - 13 -
Δημιοτπγία - Άνοιγμα ςημαυόποτ sem_open() Κλείδωμα ςημαυόποτ sem_wait() Απελετθέπωςη ςημαυόποτ sem_post() Κλείςιμο ςημαυόποτ sem_close() Διαγπαυή ςημαυόποτ sem_unlink() - 14 -
#include <sys/types.h> #include <sys/ipc.h> #include <sys/sem.h> int semget(key_t key, int nsems, int semflg); Δημιοτπγεί έναν semaphore και απφικοποιεί κάθε ςσοιφείο σοτ ςσο μηδέν. int semid = semget(ipc_private, 1, S_IRUSR S_IWUSR); Όπωρ ςσο shared memory, έσςι και εδώ σο ipcs και ipcrm μποπούν να κάνοτν list και remove semaphores - 15 -
int semop(int semid, struct sembuf *sops, unsigned nsops); Increment, decrement, or test semaphore elements for a zero value Από σο <sys/sem.h>: sops->sem_num, sops->sem_op, sops->sem_flg Αν σο sem_op είναι θεσικό ή semop() πποςθέσει ένα ςσην σιμή και ξτπάνει ση διαδικαςία ποτ πεπιμένει. Αν σο sem_op είναι απνησικό, η semop() πποςθέσει ένα ςσην σιμή και αν <0 ή semop() sets to 0 and blocks until it increases Αν σο sem_op είναι μηδέν και σο semaphore element value όφι μηδέν, η semop() blocks the calling process until the value becomes zero Αν η semop() is interrupted by a signal, it returns 1 with errno = EINTR - 16 -
struct sembuf semwait[1] = {0,-1,0}; semsignal[1] = {0,1,0}; int semid; semop(semid,semsignal,1); /* init to 1 */ while((semop(semid,semwait,1) == -1) && (errno == EINTR)); { /* Critical Section */ } while((semop(semid,semsignal,1) == -1) && (errno == EINTR)); - 17 -