ΕΠΛ371 - Ππογπαμμαηιζμόρ Σςζηημάηων Διάλεξη 16: Επικοινωνία μεηαξύ Διεπγαζιών (Inter-Process Communication (IPC)) Οςπέρ Μηνςμάηων (Message Queues) Κοινή Μνήμη (Shared Memory) Σημαηοθόποι (Semaphores) (Κεθάλαιο 15 - Stevens & Rago) Δεκήηξεο Ζετλαιηπνύξ Σάζνο νθνθιένπο 16-1
Πεξηερόκελα Δηάιεμεο Οριζμοί (Πποζδιοπιζηέρ και Κλειδιά, Διασείπιζη IPC πόπων, Διατείριζη IPC με ενηολέρ κελύθοςρ. Οσρές Μηνσμάηων (Ο.Μ.): Δομή Ο.Μ., Δημιοςπγία, Αποζηολή/ Παπαλαβή Μηνςμάηων, Πλήπερ Παπάδειγμα, Έλεγσορ Ο.Μ.. Κοινή Μνήμη: Δομή, Δημιοςπγία, Πποζάπηηζη / Απόζπαζη, Έλεγσορ, Παπάδειγμα δςο διεπγαζιών πος επικοινωνούν μέζω κοινήρ μνήμηρ Σημαηοθόροι: Δομή, Δημιοςπγία, Χειπιζμόρ, Έλεγσορ, Παπάδειγμα Εξςπηπεηηηή με ζημαηοθόποςρ 16-2
Οξηζκνί - Πξνζδηνξηζηέο θαη Κιεηδηά (Identifiers θαη Keys) Κάζε IPC* δνκή (νπξά κελπκάησλ, θνηλή κλήκε θαη ζεκαηνθόξνη) ζηνλ ππξήλα (kernel) αλαθέξεηαη κε έλα κε-αξλεηηθό αξηζκό πξνζδηνξηζηήο (identifier). Γηα παξάδεηγκα, γηα λα ζηείινπκε ή λα παξαιάβνπκε έλα κήλπκα ζε/από κηα νπξά κελπκάησλ, ην κόλν πνπ ρξεηαδόκαζηε είλαη ν πποζδιοπιζηήρ ηηρ οςπάρ (εζσηεξηθό IPC όλνκα). πλεξγαδόκελεο δηεξγαζίεο ρξεηάδνληαη έλα εμσηεξηθό όλνκα γηα λα κπνξνύλ λα ρξεζηκνπνηήζνπλ ην ίδην IPC αληηθείκελν. Επνκέλσο, έλα IPC αληηθείκελν ζπζρεηίδεηαη κε έλα κλειδί (key) πνπ δξα σο έλα εμσηεξηθό όλνκα. Σν θιεηδί απηό κεηαηξέπεηαη ζε έλα πξνζδηνξηζηή από ηνλ ππξήλα. * όπος IPC δομή θα εννοούμε ζ αςηή ηη διάλεξη ηην οςπά μηνςμάηων, κοινή μνήμη και ζημαηοθόποςρ) 16-3
Οξηζκνί - Δηαρείξηζε IPC Πόξσλ (ζπλέρεηα) Δηαρείξηζε IPC Πόξσλ Οη IPC πόξνη δνπλ εθηόο ηεο εκβέιεηαο κηαο δηεξγαζίαο. Γηα παξάδεηγκα, όηαλ δεκηνπξγνύκε κηα νπξά κελπκάησλ, ηνπνζεηνύκε θάπνηα κελύκαηα ζηελ νπξά θαη κεηά ηεξκαηίδνπκε, η οςπά μηνςμάηων και ηα πεπιεσόμενά ηηρ δε διαγπάθονηαι. Παξακέλνπλ ζην ζύζηεκα κέρξη ζςγκεκπιμένα λα δηαγξαθνύλ από κηα δηεξγαζία (θαιώληαο ζπγθεθξηκέλε IPC ιεηηνπξγία δείηε αξγόηεξα) ή επαλεθθηλώληαο (reboot) ην ζύζηεκα Δέζηε αληίζεζε κε pipes: Με ην ηέινο κηαο δηεξγαζίαο ην Pipe θαη ην πεξηερόκελν ηνπ ράλεηαη. Δέζηε αληίζεζε κε FIFO: Με ην ηέινο όισλ ησλ δηεξγαζηώλ πνπ αλαθέξνληαη ζην αξρείν (FIFO), ην πεξηερόκελν ράλεηαη, αιιά παξακέλεη ην όνομα ηνπ ζην ζύζηεκα αξρείσλ, κέρξη λα γίλεη unlink 16-4
Οξηζκνί - Δηαρείξηζε IPC Πόξσλ (ζπλέρεηα) Οη IPC δνκέο δελ είλαη αλαγλσξίζηκεο κε νλόκαηα ζην ζύζηεκα αξρείσλ (δε ρξεζηκνπνηνύλ πεξηγξαθείο αξρείσλ). Δε κπνξνύκε λα έρνπκε πξόζβαζε ζ απηέο θαη λα αιιάμνπκε ηηο ηδηόηεηεο κε θιήζεηο ζπζηήκαηνο όπσο έρνπκε κάζεη κέρξη ηώξα (open, write, close, ). Νέεο θιήζεηο-ιεηηνπξγίεο ζπζηήκαηνο έρνπλ πξνζηεζεί ζηνλ ππξήλα γηα ππνζηήξημε απηώλ ησλ IPC αληηθεηκέλσλ ( δείηε αξγόηεξα) 16-5
Δηαρείξηζε IPC κε εληνιέο θειύθνπο Αλάγθε γηα δηαρείξηζε IPC Πόξσλ Δηαγξαθή πόξσλ πνπ έκεηλαλ ιόγσ δηεξγαζηώλ πνπ δελ αληηδξνύλ (irresponsive ή crashes) Έιεγρνο αξηζκνύ πθηζηάκελσλ πόξσλ ηνπ θάζε ηύπνπ (εηδηθά γηα λα βξνύκε αλ ν θαζνιηθόο πεξηνξηζκόο ηνπ ζπζηήκαηνο έρεη θζάζεη) Δπν utilities ζπζηήκαηνο έρνπλ δεκηνπξγεζεί γηα ηελ πην πάλσ δηαρείξηζε: Δέζηε man για λεπηομέπειερ Εληνιή ipcrm (όμοιο με unlink πάνω ζε όνομα απσείος) Δέσεηαι ηον ηύπο ηος πόπος ( msg, shm, sem ) και ηον πποζδιοπιζηή ή ηο κλειδί ηος πόπος και διαγπάθει ηο ζςγκεκπιμένο πόπο από ηο ζύζηημα ( ππέπει να έσοςμε ηα αναγκαία δικαιώμαηα ππόζβαζηρ) 16-6
Δηαρείξηζε IPC κε εληνιέο θειύθνπο (ζπλέρεηα) Εληνιή ipcs Δείσνει ζηαηιζηικέρ για κάθε ηύπο IPC πόπος πος ςπάπσει ζηο ζύζηημα bash-3.1$ ipcs ------ Shared Memory Segments -------- key shmid owner perms bytes nattch status ------ Semaphore Arrays -------- key semid owner perms nsems ------ Message Queues -------- key msqid owner perms used-bytes messages 16-7
Δηαρείξηζε IPC κε εληνιέο θειύθνπο (ζπλέρεηα) Εληνιή ipcs -l Δείσνει ηοςρ καθολικά πεπιοπιζμούρ ηος ζςζηήμαηορ ζηοςρ IPC πόποςρ. bash-3.1$ ipcs -l ------ Shared Memory Limits -------- max number of segments = 4096 max seg size (kbytes) = 32768 max total shared memory (kbytes) = 8388608 min seg size (bytes) = 1 ------ Semaphore Limits -------- max number of arrays = 128 max semaphores per array = 250 max semaphores system wide = 32000 max ops per semop call = 32 semaphore max value = 32767 ------ Messages: Limits -------- max queues system wide = 16 max size of message (bytes) ΕΠΛ 371 = 8192 Ππογπαμμαηιζμόρ Σςζηημάηων default max size of queue (bytes) = 16384 16-8
Οπξέο Μελπκάησλ Απαίηεζε: #include <sys/msg.h> Οπξά Μελπκάησλ Μηα ζπλδεδεκέλε ιίζηα κελπκάησλ απνζεθεπκέλε ζηνλ ππξήλα θαη ε νπνία αλαγλσξίδεηαη κε έλα πξνζδηνξηζηή νπξάο κελπκάησλ. Χξεζηκεύεη ζηελ αληαιιαγή κελπκάησλ κεηαμύ δηεξγαζηώλ. πγρξνληζκόο πξνζθέξεηαη αςηόμαηα από ηνλ ππξήλα. Νέα κελύκαηα πξνζζέηνληαη ζην ηέινο ηεο νπξάο. 16-9
Δνκή Μελύκαηνο Έλα κήλπκα απνηειείηαη από ηνλ ηύπν κελύκαηνο (ζεηηθόο long αθέξαηνο) θαη ηα δεδνκέλα (data) ηνπ κελύκαηνο. /* Template for struct to be used as argument for `msgsnd' and `msgrcv'. */ struct msgbuf { long int mtype; /* type of received/sent message */ char mtext[1]; /* text of the message */ }; mtext[1] ςποδηλώνει ηο ελάσιζηο μέγεθορ μηνύμαηορ 16-10
Δνκή Μελύκαηνο (ζπλέρεηα) Μελύκαηα κπνξνύλ λα αλαθηεζνύλ από ηελ θεθαιή ηεο νπξάο θαη λα πξνζηεζνύλ ζην ηέινο ηεο νπξάο, είηε δεηώληαο ζπγθεθξηκέλν ηύπο κελύκαηνο. Π.ρ. Μηα server δηεξγαζία κπνξεί λα θαηεπζύλεη ηελ θπθινθνξία κελπκάησλ κεηαμύ clients ζηελ νπξά κελπκάησλ ηεο, ρξεζηκνπνηώληαο ην PID ηεο client δηεξγαζίαο σο ηνλ ηύπν κελπκάησλ. ηε ζπλέρεηα, κπνξεί λα αλαθηήζεη ηα κελύκαηα από ηελ νπξά από ζπγθεθξηκέλν client. 16-11
Δνκή Οπξάο Μελπκάησλ Κάζε νπξά ζπζρεηίδεηαη κε ηελ αθόινπζε msqid_ds δνκή (νξίδεη ηελ πθηζηάκελε θαηάζηαζε ηεο νπξάο): /* Structure of record for one message inside the kernel. */ struct msqid_ds { struct ipc_perm msg_perm; /* structure describing operation permission */ time_t msg_stime; /* time of last msgsnd command */ time_t msg_rtime; /* time of last msgrcv command */ time_t msg_ctime; /* time of last change */ unsigned long int msg_cbytes; /* current number of bytes on queue */ msgqnum_t msg_qnum; /* number of messages currently on queue */ msglen_t msg_qbytes; /* max number of bytes allowed on queue */ pid_t msg_lspid; /* pid of last msgsnd() */ pid_t msg_lrpid; /* pid of last msgrcv() */ }; 16-12
Δεκηνπξγία Οπξάο Μελπκάησλ Κιήζε ζπζηήκαηνο msgget() #include <sys/msg.h> int msgget(key_t key, int flag); Επηζηξέθεη: πξνζδηνξηζηή νπξάο ζε επηηπρία ή -1 ζε πεξίπησζε ιάζνπο Αλνίγεη κηα πθηζηάκελε νπξά ή δεκηνπξγεί κηα λέα νπξά. Ο πξνζδηνξηζηήο ηεο νπξάο κελπκάησλ πνπ επηζηξέθεηαη αληηζηνηρεί ζην κλειδί Σν key θαη flag εμεγνύληαη ζηηο επόκελεο δηαθάλεηεο 16-13
Δεκηνπξγία Οπξάο Μελπκάησλ (ζπλέρεηα) Η παξάκεηξνο key είλαη έλαο κνλαδηθόο πξνζδηνξηζηήο γηα ηελ νπξά πνπ ζέινπκε λα δεκηνπξγήζνπκε. Οπνηαδήπνηε άιιε δηεξγαζία ζέιεη λα ζπλδεζεί κε απηή ηελ νπξά πξέπεη λα ρξεζηκνπνηήζεη ην ίδην θιεηδί. Σν κλειδί κπνξεί λα δνζεί από ην ρξήζηε ζαλ έλα ζεηηθό αθέξαην πνπ έρεη ζπκθσλεζεί κεηαμύ ησλ νληνηήησλ πνπ ζα ρξεζηκνπνηήζνπλ ηελ θνηλή νπξά κελπκάησλ. Π.ρ. νξηζκόο ηνπ θιεηδηνύ ζε κηα θνηλή επηθεθαιίδα (header) Πξόβιεκα όηαλ ην θιεηδί απηό έρεη ήδε ζπζρεηηζηεί κε κηα άιιε νπξά κελπκάησλ. Αλ ζέινπκε ν ππξήλαο λα δεκηνπξγήζεη ην κλειδί ππάξρεη θαη ε θιήζε ζπζηήκαηνο ftoc() 16-14
Δεκηνπξγία Οπξάο Μελπκάησλ (ζπλέρεηα) Σν θιεηδί κπνξεί επίζεο λα είλαη IPC_PRIVATE ( sys/ipc.h). Με απηό ηνλ ηξόπν, ην θιεηδί IPC_PRIVATE εγγπάηαη ηε δεκηνπξγία κηαο λέαο IPC δνκήο νπξάο. Σν θιεηδί IPC_PRIVATE επίζεο ρξεζηκνπνηείηαη ζε κηα ζρέζε παηέξα-παηδηνύ. Ο παηέξαο δεκηνπξγεί κηα λέα νπξά νξίδνληαο ην θιεηδί σο IPC_PRIVATE, θαη ν πξνζδηνξηζηήο πνπ επηζηξέθεηαη είλαη ηόηε δηαζέζηκνο ζην παηδί κεηά ην fork(). 16-15
Δεκηνπξγία Οπξάο Μελπκάησλ (ζπλέρεηα) Η παξάκεηξνο flag είλαη έλαο αθέξαηνο όπνπ ηίζεληαη ηα επηζπκεηά δηθαηώκαηα πξνζηαζίαο (read/write) ηεο νπξάο κελπκάησλ (ζε octal ηηκή), θαζώο επίζεο θαη πξόζζεηεο απαηηήζεηο (ππό ηε κνξθή δηάδεπμεο ζπκβνιηθώλ νλνκάησλ sys/ipc.h) ζρεηηθέο κε ηε δεκηνπξγία ηεο νπξάο κελπκάησλ, όπσο: IPC_CREAT Αλ δελ ππάξρεη πόξνο (νπξά κελπκάησλ) πνπ αληηζηνηρεί ζην κλειδί, λα δεκηνπξγεζεί λένο (αληί λα επηζηξαθεί ιάζνο) ελώ αλ ππάξρεη ηέηνηνο πόξνο, λα πξνζπειαζζεί απηόο. IPC_EXCL ε ζπλδπαζκό κε ην πξνεγνύκελν, αλ δελ ππάξρεη πόξνο, λα δεκηνπξγεζεί. Αλ ππάξρεη όκσο, λα επηζηξαθεί ιάζνο. 16-16
Δεκηνπξγία Οπξάο Μελπκάησλ (ζπλέρεηα) Παξαδείγκαηα: #include <stdio.h> /* standard I/O routines. */ #include <sys/types.h> /* standard system data types. */ #include <sys/ipc.h> /* common system V IPC structures. */ #include <sys/msg.h> /* message-queue specific functions. */ /* create a private message queue, with access only to the owner. */ int queue_id = msgget(ipc_private, 0600); /* <-- this is an octal number. */ if (queue_id == -1) { perror("msgget"); exit(1); } key_t key = ftok("/home/cchrys/somefile", 'b'); int queue_id = msgget(key, 0666 IPC_CREAT); 16-17
Απνζηνιή κελπκάησλ Κιήζε ζπζηήκαηνο msgsnd() writing to a queue #include <sys/msg.h> int msgsnd(int msqid, const void *ptr, size_t nbytes, int flag); Επηζηξέθεη -1 ζε πεξίπησζε ιάζνπο ή 0 ζε πεξίπησζε επηηπρίαο msgid Ο πξνζδηνξηζηήο ηεο νπξάο κελπκάησλ πνπ ζέινπκε λα γξάςνπκε (ζηείινπκε) έλα κήλπκα (επηζηξέθεηαη από ηε θιήζε ζπζηήκαηνο msgget() ) ptr Έλαο δείθηεο ζηε δνκή κελύκαηνο πνπ ζέινπκε λα γξάςνπκε ζηελ νπξά nbytes Μέγεζνο ζε bytes ησλ δεδνκέλσλ ηνπ κελύκαηνο πνπ ζα πξνζζέζνπκε ζηελ νπξά 16-18
flag Απνζηνιή κελπκάησλ (ζπλέρεηα) Η ηηκή 0 κπνξεί λα ηεζεί αλ δελ έρνπκε θάπνην flag. Σν flag IPC_NOWAIT ( sys/ipc.h) κπνξεί λα νξηζζεί. Εάλ ε νπξά κελπκάησλ είλαη γεκάηε (είηε ν ζπλνιηθόο αξηζκόο κελπκάησλ ζηελ νπξά έρεη θζάζεη ην επηηξεπηό όξην ηνπ ζπζηήκαηνο, είηε ν ζπλνιηθόο αξηζκόο bytes ζηελ νπξά έρεη θζάζεη ην επηηξεπηό όξην), κε ην λα νξίζνπκε ην flag IPC_NOWAIT πξνθαιεί ηε msgsnd() λα επηζηξέςεη άκεζα κε ην ιάζνο EAGAIN. Εάλ ην flag IPC_NOWAIT δελ νξηζζεί, ηόηε είκαζηε κπινθαξηζκέλνη κέρξη» λα βξεζεί δηαζέζηκνο ρώξνο γηα ην κήλπκα» ε νπξά λα δηαγξαθεί από ην ζύζηεκα (ην ιάζνο EIDRM επηζηξέθεη)» ή έλα ζήκα πηάλεηαη θαη ην signal handler επηζηξέθεη (ην ιάζνο EINTR interrupt επηζηξέθεη) 16-19
Απνζηνιή κελπκάησλ (ζπλέρεηα) Παξάδεηγκα: /* first, define the message string */ char* msg_text = "hello world"; /* allocate a message with enough space for length of string and one extra byte for the terminating null character. */ struct msgbuf* msg = (struct msgbuf*)malloc(sizeof(struct msgbuf) + strlen(msg_text)); /* set the message type. for example - set it to '1'. */ msg->mtype = 1; /* finally, place the "hello world" string inside the message. */ strcpy(msg->mtext, msg_text); /*we use a message size one larger than the length of the string, since we're also sending the null character */ int rc = msgsnd(queue_id, msg, strlen(msg_text)+1, 0); if (rc == -1) { perror("msgsnd"); exit(1); } 16-20
Παξαιαβή κελπκάησλ Κιήζε ζπζηήκαηνο msgrcv() reading from a queue #include <sys/msg.h> ssize_t msgrcv(int msqid, void *ptr, size_t nbytes, long type, int flag); Επηζηξέθεη -1 ζε πεξίπησζε ιάζνπο ή ην κέγεζνο ησλ δεδνκέλσλ ηνπ κελύκαηνο ζε πεξίπησζε επηηπρίαο msgid Ο πξνζδηνξηζηήο ηεο νπξάο κελπκάησλ πνπ ζέινπκε λα δηαβάζνπκε (παξαιάβνπκε) έλα κήλπκα (επηζηξέθεηαη από ηε θιήζε ζπζηήκαηνο msgget() ) ptr Έλαο δείθηεο ζηε δνκή κελύκαηνο πνπ ζέινπκε λα θπιάμνπκε ηνλ ηύπν θαη ηα δεδνκέλα ηνπ κελύκαηνο πνπ έρνπκε δηαβάζεη κε επηηπρία από ηελ νπξά nbytes Μέγεζνο ζε bytes ησλ δεδνκέλσλ ζηε δνκή κελύκαηνο. 16-21
Παξαιαβή κελπκάησλ (ζπλέρεηα) Εάλ ην κήλπκα πνπ παξαιακβάλεηαη/δηαβάδεηαη είλαη κεγαιύηεξν από ηελ παξάκεηξν nbytes θαη ην MSG_NOERROR ( sys/msg.h) flag νξίδεηαη, ηόηε ην κήλπκα θόβεηαη (δε δίλεηαη θακία εηδνπνίεζε θαη ην ππόινηπν ηνπ κελύκαηνο ράλεηαη). Εάλ ην κήλπκα είλαη πνιύ κεγάιν θαη ην MSG_NOERROR flag δελ νξίδεηαη, ηόηε ην ιάζνο E2BIG επηζηξέθεηαη. 16-22
Παξαιαβή κελπκάησλ (ζπλέρεηα) Η παξάκεηξνο type νξίδεη πνην κήλπκα ζέινπκε: type == 0 Επηζηξέθεηαη ην πξώην κήλπκα ζηελ νπξά type > 0 Επηζηξέθεηαη ην πξώην κήλπκα ζηελ νπξά ηνπ νπνίνπ ν ηύπνο είλαη ίζν κε ηελ παξάκεηξν type < 0 Επηζηξέθεηαη ην πξώην κήλπκα ζηελ νπξά ηνπ νπνίνπ ν ηύπνο είλαη ε ρακειόηεξε-ηηκή κηθξόηεξε ή ίζε κε ηελ απόιπηε ηηκή ηεο παξακέηξνπ Γηα παξάδεηγκα: ν ηύπορ κπνξεί λα είλαη κηα ηηκή πξνηεξαηόηεηαο, αλ ε εθαξκνγή αλαζέηεη πξνηεξαηόηεηεο ζηα κελύκαηα. ν ηύπορ κπνξεί λα πεξηέρεη ηελ ηαπηόηεηα ηεο δηεξγαζίαο ελόο client, εάλ κηα νπξά κελπκάησλ ρξεζηκνπνηείηαη από πνιιαπινύο clients θαη έλα server. 16-24
Πιήξεο παξάδεηγκα νπξάο κελπκάησλ Σν queue_sender.c δεκηνπξγεί κηα νπξά κελπκάησλ θαη ζηέιιεη κελύκαηα κε δηαθνξεηηθέο πξνηεξαηόηεηεο ζηελ νπξά. Σν queue_reader.c δηαβάδεη ηα κελύκαηα από ηελ νπξά θαη ηα ηππώλεη. Παίξλεη κηα ηηκή ζηε γξακκή εληνιήο πνπ αληηπξνζσπεύεη ηελ πξνηεξαηόηεηα ησλ κελπκάησλ πνπ ζέινπκε λα δηαβάζνπκε. Σξέρνπκε πνιιαπιά αληίγξαθα ηνπ πξνγξάκκαηνο απηνύ ηαπηόρξνλα. Σέηνηνο κεραληζκόο κπνξεί λα ρξεζηκνπνηεζεί από έλα ζύζηεκα ζην νπνίν πνιινί clients κπνξνύλ λα ζηέιινπλ αηηήκαηα δηαθόξσλ ηύπσλ, ηα νπνία ρξεηάδνληαη δηαθνξεηηθή αληηκεηώπηζε. 16-25
Πιήξεο παξάδεηγκα νπξάο κελπκάησλ (ζπλέρεηα) /* * queue_sender.c - a program that writes messages with one of 3 identifiers to a message queue. */ #include <stdio.h> #include <stdlib.h> #include <sys/types.h> #include <sys/ipc.h> #include <sys/msg.h> #include <string.h> #include "queue_defs.h" int main(int argc, char* argv[]) { int queue_id; /* ID of the created queue.*/ struct msgbuf* msg; /* structure used for sent messages. */ int i; /* loop counter */ int rc; /* error code returned by system calls. */ /* create a public message queue, with access only to the owning user. */ queue_id = msgget(queue_id, IPC_CREAT IPC_EXCL 0600); if (queue_id == -1) { perror("main: msgget"); exit(1); } printf("message queue created, queue id '%d'.\n", queue_id); msg = (struct msgbuf*)malloc(sizeof(struct msgbuf)+max_msg_size); } /* form a loop of creating messages and sending them. */ for (i=1; i <= NUM_MESSAGES; i++) { msg->mtype = (i % 3) + 1; /* create message type between '1' and '3' */ sprintf(msg->mtext, "hello world - %d", i); rc = msgsnd(queue_id, msg, strlen(msg- >mtext)+1, 0); if (rc == -1) { perror("main: msgsnd"); exit(1); } } /* free allocated memory. */ free(msg); printf("generated %d messages, exiting.\n", NUM_MESSAGES); return 0; 16-26
Πιήξεο παξάδεηγκα νπξάο κελπκάησλ (ζπλέρεηα) /* * queue_reader.c - a program that reads messages with a given identifier * off of a message queue. */ #include <stdio.h> /* standard I/O functions. */ #include <stdlib.h> /* malloc(), free() etc. */ #include <unistd.h> /* sleep(), etc. */ #include <sys/types.h> /* various type definitions. */ #include <sys/ipc.h> /* general SysV IPC structures */ #include <sys/msg.h> /* message queue functions and structs. */ #include "queue_defs.h" /* definitions shared by both programs */ int main(int argc, char* argv[]) { int queue_id; /* ID of the created queue. */ struct msgbuf* msg; /* structure used for received messages. */ int rc; /* error code returned by system calls. */ int msg_type; /* type of messages we want to receive. */ /* read message type from command line */ if (argc!= 2) { fprintf(stderr, "Usage: %s <message type>\n", argv[0]); fprintf(stderr, " <message type> must be between 1 and 3.\n"); exit(1); } msg_type = atoi(argv[1]); if (msg_type < 1 msg_type > 3) { fprintf(stderr, "Usage: %s <message type>\n", argv[0]); fprintf(stderr, " <message type> must be between 1 and 3.\n"); exit(1); } 16-27
Πιήξεο παξάδεηγκα νπξάο κελπκάησλ (ζπλέρεηα) /* access the public message queue that the sender program created. */ queue_id = msgget(queue_id, 0); if (queue_id == -1) { perror("main: msgget"); exit(1); } printf("message queue opened, queue id '%d'.\n", queue_id); msg = (struct msgbuf*)malloc(sizeof(struct msgbuf)+max_msg_size); } /* form a loop of receiving messages and printing them out. */ while (1) { rc = msgrcv(queue_id, msg, MAX_MSG_SIZE+1, msg_type, IPC_NOWAIT); if (rc == -1) { perror("main: msgrcv"); exit(1); } printf("reader '%d' read message: '%s'\n", msg_type, msg->mtext); /* slow down a little... */ sleep(1); } /* NOT REACHED */ return 0; 16-28
Πιήξεο παξάδεηγκα νπξάο κελπκάησλ (ζπλέρεηα) #ifndef QUEUE_DEFS_H # define QUEUE_DEFS_H /* * queue_defs.h - common macros and definitions for the public message * queue example. */ #define QUEUE_ID 137 /* ID of queue to generate. */ #define MAX_MSG_SIZE 200 /* size (in bytes) of largest message we'll send.*/ #define NUM_MESSAGES 100 /* number of messages the sender program will send. */ struct msgbuf { long int mtype; /* type of received/sent message */ char mtext[1]; /* text of the message */ }; #endif /* QUEUE_DEFS_H */ 16-29
bash-3.1$./sender bash-3.1$./reader 1 message queue opened, queue id '98304'. Reader '1' read message: 'hello world - 3' Reader '1' read message: 'hello world - 6' Reader '1' read message: 'hello world - 9' Reader '1' read message: 'hello world - 12' Reader '1' read message: 'hello world - 15' Reader '1' read message: 'hello world - 18' Reader '1' read message: 'hello world - 21' Reader '1' read message: 'hello world - 24' Reader '1' read message: 'hello world - 27' Reader '1' read message: 'hello world - 30' Reader '1' read message: 'hello world - 33' Reader '1' read message: 'hello world - 36' Reader '1' read message: 'hello world - 39' Reader '1' read message: 'hello world - 42' Reader '1' read message: 'hello world - 45' Reader '1' read message: 'hello world - 51' Reader '1' read message: 'hello world - 57' Reader '1' read message: 'hello world - 63' Reader '1' read message: 'hello world - 69' Reader '1' read message: 'hello world - 75' Reader '1' read message: 'hello world - 81' Reader '1' read message: 'hello world - 87' Reader '1' read message: 'hello world - 93' Reader '1' read message: 'hello world - 99' main: msgrcv: No message of desired type bash-3.1$ Terminal 1 Πιήξεο παξάδεηγκα νπξάο κελπκάησλ (ζπλέρεηα) bash-3.1$ gcc queue_sender.c -o sender bash-3.1$ gcc queue_reader.c -o reader Terminal 2 bash-3.1$./reader 1 message queue opened, queue id '98304'. Reader '1' read message: 'hello world - 48' Reader '1' read message: 'hello world - 54' Reader '1' read message: 'hello world - 60' Reader '1' read message: 'hello world - 66' Reader '1' read message: 'hello world - 72' Reader '1' read message: 'hello world - 78' Reader '1' read message: 'hello world - 84' Reader '1' read message: 'hello world - 90' Reader '1' read message: 'hello world - 96' main: msgrcv: No message of desired type bash-3.1$ 16-30
Πιήξεο παξάδεηγκα νπξάο κελπκάησλ (ζπλέρεηα) bash-3.1$ ipcs -q ------ Message Queues -------- key msqid owner perms used-bytes messages 0x00000089 98304 cspgcc1 600 1134 67 bash-3.1$ ipcrm -q 98304 16-31
Έιεγρνο Οπξάο Μελπκάησλ Κιήζε ζπζηήκαηνο msgctl() #include <msg.h> int msgctl(int msqid, int cmd, struct msqid_ds *buf); Επηζηξέθεη -1 ζε πεξίπησζε ιάζνπο ή 0 ζε πεξίπησζε επηηπρίαο Η msgctl() αιιάδεη ηα δηθαηώκαηα πξόζβαζεο θαη άιια ραξαθηεξηζηηθά κηαο νπξάο κελπκάησλ. Εθηειεί ηελ ελέξγεηα (εληνιή) πνπ νξίδεηαη ζηελ παξάκεηξν cmd επάλσ ζηελ νπξά κελπκάησλ πνπ αληηζηνηρεί ζηνλ πξνζδηνξηζηή πνπ νξίδεηαη ζηελ παξάκεηξν msqid. 16-32
Έιεγρνο Οπξάο Μελπκάησλ (ζπλέρεηα) Η παξάκεηξνο cmd κπνξεί λα είλαη: IPC_STAT Φέξε ηε msqid_ds δνκή ηεο ζπγθεθξηκέλεο νπξάο, απνζεθεύνληάο ηελ ζηε δνκή πνπ δείρλεηαη από ηε παξάκεηξν buf. IPC_SET διδ, θύιαμε ησλ πιεξνθνξηώλ ζρεηηθά κε ηελ θαηάζηαζε ηεο νπξάο ζηε δνκή δεδνκέλσλ πνπ δείρλεηαη από ηε buf. Ρύζκηζε ησλ δηθαησκάησλ πξόζβαζεο, ηδηνθηήηε, νκάδα, θαη ηνπ επηηξεπηνύ κέγηζηνπ αξηζκνύ bytes ηεο msqid_ds δνκήο ηεο ζπγθεθξηκέλεο νπξάο από ηε buf ανηιγπαθή ηων πιο πάνω πεδίων από ηη δομή πος δείσνεηαι από ηη buf ζηη msqid_ds δνκή πνπ ζπζρεηίδεηαη κε ηε ζπγθεθξηκέλε νπξά 16-33
Έιεγρνο Οπξάο Μελπκάησλ (ζπλέρεηα) IPC_RMID Δηαγξάθεη (θαηαζηξέθεη) ηελ νπξά κελπκάησλ από ην ζύζηεκα καδί κε όια ηα δεδνκέλα πνπ βξίζθνληαη ζ απηή. Η αθαίξεζε είλαη άκεζε. Οπνηαδήπνηε άιιε δηεξγαζία αθόκα ρξεζηκνπνηεί ηελ νπξά κελπκάησλ, ζα πάξεη έλα κήλπκα (EIDRM identifier removed ) ζηελ επόκελε πξνζπάζεηα ιεηηνπξγίαο ζηελ νπξά. Η παξάκεηξνο buff ηίζεηαη 0 (null) 16-34
Έιεγρνο Οπξάο Μελπκάησλ (ζπλέρεηα) Παξαδείγκαηα: #include<sys/types.h> #include <sys/ipc.h> #include <sys/msg.h>... if (msgctl(msqid, IPC_STAT, &buf) == -1) { } perror("msgctl: msgctl failed"); exit(1);... if (msgctl(msqid, IPC_SET, &buf) == -1) { perror("msgctl: msgctl failed"); exit(1); }... if (msgctl(msqid, IPC_RMID, NULL) == -1) { perror("msgctl: msgctl failed"); exit(1); } 16-35
Κνηλή Μλήκε Απαίηεζε: #include <sys/shm.h> Δπλαηόηεηα επηθνηλσλίαο κεηαμύ δηεξγαζηώλ κέζσ θαηαρώξεζεο θαη αλάγλσζεο πιεξνθνξηώλ ζε πεξηνρή κλήκεο πνπ είλαη πξνζπειάζηκε από όιεο ηηο δηεξγαζίεο πνπ έρνπλ δηθαίσκα. Αλάγθε ζπγρξνληζκνύ ησλ δηεξγαζηώλ, ζπλήζσο κέζσ ζεκαηνθόξσλ. 16-36
Κνηλή Μλήκε (ζπλέρεηα) αληίζεζε κε ηελ νπξά κελπκάησλ, πνπ αληηγξάθεη δεδνκέλα από ηε δηεξγαζία ζηε κλήκε κέζα ζηνλ ππξήλα, ε θνηλή κλήκε είλαη απεπζείαο πξνζβάζηκε. Η θνηλή κλήκε βξίζθεηαη ζηε κλήκε δηεξγαζίαο ηνπ ρξήζηε θαη ηόηε κνηξάδεηαη κεηαμύ άιισλ δηεξγαζηώλ. 16-37
Κνηλή Μλήκε (ζπλέρεηα) Κνηλό ηκήκα κλήκεο κεηαμύ δηεξγαζηώλ Create MAX Shared Memory (unique key) ptr Attach 0 Attach ptr Process 1 Process 2 ptr ptr ptr Process 3 Process 4 Process 5 16-38
Δνκή Κνηλήο Μλήκεο Ο ππξήλαο δηαηεξεί κηα δνκή κε ηα αθόινπζα κέιε γηα θάζε ηκήκα θνηλήο κλήκεο πνπ δεκηνπξγείηαη: struct shmid_ds { struct ipc_perm shm_perm; /* operation permission struct */ size_t shm_segsz; /* size of segment in bytes */ _time_t shm_atime; /* time of last shmat() */ _time_t shm_dtime; /* time of last shmdt() */ _ time_t shm_ctime; /* time of last change by shmctl() */ pid_t shm_cpid; /* pid of creator */ pid_t shm_lpid; /* pid of last shmop */ shmatt_t shm_nattch; /* number of current attaches */... }; 16-39
Δεκηνπξγία Κνηλήο Μλήκεο Κιήζε ζπζηήκαηνο shmget() #include <sys/shm.h> int shmget(key_t key, size_t size, int flag); Επηζηξέθεη: πξνζδηνξηζηή θνηλήο κλήκεο ζε επηηπρία ή -1 ζε πεξίπησζε ιάζνπο Δεκηνπξγία ηκήκαηνο θνηλήο κλήκεο Επηζηξέθεη έλα πξνζδηνξηζηή γηα ηελ θνηλή κλήκε κεγέζνπο size (ζε bytes) πνπ αληηζηνηρεί ζην θιεηδί key. ηελ παξάκεηξν flag ηίζεληαη ηα επηζπκεηά δηθαηώκαηα πξνζηαζίαο θαζώο θαη πξόζζεηεο απαηηήζεηο (IPC_CREAT θαη IPC_EXCL, κε ηελ ίδηα ζεκαζία πνπ έρνπλ θαη ζηηο νπξέο κελπκάησλ) ζρεηηθέο κε ηε δεκηνπξγία ηεο θνηλήο κλήκεο. 16-40
Δεκηνπξγία Κνηλήο Μλήκεο (ζπλέρεηα) Εάλ έλα λέν ηκήκα θνηλήο κλήκεο δεκηνπξγείηαη, πξέπεη λα δεισζεί έλα size. Εάλ παξαπέκπνπκε ζε πθηζηάκελν ηκήκα θνηλήο κλήκεο (πειάηεο), κπνξνύκε λα νξίζνπκε ην size σο 0. Όηαλ έλα λέν ηκήκα θνηλήο κλήκεο δεκηνπξγείηαη, ηα πεξηερόκελα ηνπ ηκήκαηνο αξρηθνπνηνύληαη κε 0s. Παράδειγμα: /* this variable is used to hold the returned segment identifier. */ int shm_id; /* allocate a shared memory segment with size of 2048 bytes, accessible only to the current user. */ key_t key = ftok( /home/user/somefile.txt, R ); shm_id = shmget(key, 2048, IPC_CREAT IPC_EXCL 0600); if (shm_id == -1) { perror("shmget: "); exit(1); } 16-41
Πξνζάξηεζε Κνηλήο Μλήκεο Κιήζε ζπζηήκαηνο shmat() #include <sys/shm.h> void *shmat(int shmid, const void *addr, int flag); Επηζηξέθεη: δείθηε ζην ηκήκα θνηλήο κλήκεο ζε πεξίπησζε επηηπρίαο, αιιηώο -1 Όηαλ έλα ηκήκα θνηλήο κλήκεο δεκηνπξγείηαη, κηα δηεξγαζία πξνζαξηά ην ηκήκα ζην ρώξν δηεπζύλζεώλ ηεο (address space). Η shmat() πξνζαξηά ηελ θνηλή κλήκε πνπ αληηζηνηρεί ζηνλ πξνζδηνξηζηή shmid ζηελ πεξηνρή κλήκεο πνπ έρεη πξόζβαζε ε θαινύζα δηεξγαζία θαη επηζηξέθεη ηελ θαηάιιειε δηεύζπλζε. Μέζσ ησλ παξακέηξσλ addr θαη flag κπνξεί λα δεηεζεί ε πξνζάξηεζε ζε ζπγθεθξηκέλε πεξηνρή κλήκεο, αιιά είλαη πην ζύλεζεο θαη νξζό λα αθεζεί ε επηινγή απηή ζηνλ ππξήλα ζέηνληαο 0 θαη ζηηο δπν παξακέηξνπο. Εάλ ην flag ηίζεηαη σο SHM_RDONLY, ην ηκήκα είλαη κόλν γηα read, αιιηώο είλαη read-write. 16-42
Πξνζάξηεζε Κνηλήο Μλήκεο high address (ζπλέρεηα) argv, argc and envir. variables STACK shared memory heap Uninitialized Data (BSS) Initialized Data Memory layout TEXT low address 16-43
Απόζπαζε Κνηλήο Μλήκεο Κιήζε ζπζηήκαηνο shmdt() #include <sys/shm.h> int shmdt(void *addr); Επηζηξέθεη: 0 ζε πεξίπησζε επηηπρίαο, αιιηώο -1 ζε πεξίπησζε ιάζνπο Η παξάκεηξνο addr είλαη ε δηεύζπλζε πνπ επηζηξάθεθε από ηελ θιήζε ζπζηήκαηνο shmat() Απνζπά ηελ πξνζαξηεκέλε, ζηε δηεύζπλζε addr, θνηλή κλήκε, όηαλ ε ζπγθεθξηκέλε δηεξγαζία πνπ ηελ θαιεί έρεη ηειεηώζεη από ην λα ρξεζηκνπνηεί ηελ θνηλή κλήκε. Απηό δε δηαγξάθεη ηνλ πξνζδηνξηζηή θαη ηε ζρεηηθή IPC δνκή από ην ζύζηεκα. Ο πξνζδηνξηζηήο παξακέλεη λα πθίζηαηαη κέρξη θάπνηα δηεξγαζία ηε δηαγξάςεη ζπγθεθξηκέλα. 16-44
Έιεγρνο Κνηλήο Μλήκεο Κιήζε ζπζηήκαηνο shmctl() #include <shm.h> int shmctl(int shmid, int cmd, struct shmid_ds *buf); Επηζηξέθεη -1 ζε πεξίπησζε ιάζνπο ή 0 ζε πεξίπησζε επηηπρίαο Εθηειεί ηελ ελέξγεηα cmd ζηελ θνηλή κλήκε πνπ αληηζηνηρεί ζηνλ πξνζδηνξηζηή shmid Αληίζηνηρα κε ηηο δπλαηόηεηεο πνπ ππάξρνπλ γηα ηηο νπξέο κελπκάησλ (κέζσ ηεο msgctl), κε ηελ ελέξγεηα IPC_STAT ζπκπιεξώλνληαη ηα πεδία ηεο δνκήο *buf κε ηα ραξαθηεξηζηηθά ηεο θνηλήο κλήκεο, ελώ κε ηελ ελέξγεηα ηipc_set ξπζκίδνληαη ζπγθεθξηκέλα πεδία από ηε δομή πος δείσνεηαι από ηη buf ζηη shmid_ds δνκή πνπ ζπζρεηίδεηαη κε ην ζπγθεθξηκέλν ηκήκα θνηλήο κλήκεο. Η ζπλεζέζηεξε ελέξγεηα είλαη ε IPC_RMID πνπ θαηαζηξέθεη ηελ θνηλή κλήκε. 16-45
Παξάδεηγκα δπν δηεξγαζηώλ πνπ επηθνηλσλνύλ κέζσ θνηλήο κλήκεο /**** shm_server.c ****/ #include <sys/types.h> #include <sys/ipc.h> #include <sys/shm.h> #include <stdio.h> #include <stdlib.h> #define SHMSZ 27 main() { char c; int shmid; key_t key; char *shm, *s; /* We'll name our shared memory segment * "5678". */ key = 5678; /* Create the segment. */ if ((shmid = shmget(key, SHMSZ, IPC_CREAT 0666)) < 0) { perror("shmget"); exit(1); } /* Now we attach the segment to our data space. */ if ((shm = shmat(shmid, ΕΠΛ 371 NULL, Ππογπαμμαηιζμόρ 0)) == (char Σςζηημάηων *) -1) { perror("shmat"); exit(1); } 16-46
Παξάδεηγκα δπν δηεξγαζηώλ πνπ επηθνηλσλνύλ κέζσ θνηλήο κλήκεο (ζπλέρεηα) /* Now put some things into the memory for the other process to read. */ s = shm; for (c = 'a'; c <= 'z'; c++) *s++ = c; *s = \0'; /* Finally, we wait until the other process changes the first character of our memory to '*', indicating that it has read what we put there. */ while (*shm!= '*') sleep(1); /* detach from the segment: */ if (shmdt(shm) == -1) perror("shmdt"); /* delete τhe segment */ if( shmctl(shmid, IPC_RMID, NULL) == -1) { perror("shmctl"); exit(1); } return 0; } 16-47
Παξάδεηγκα δπν δηεξγαζηώλ πνπ επηθνηλσλνύλ κέζσ θνηλήο κλήκεο /**** shm_client.c ****/ #include <sys/types.h> #include <sys/ipc.h> #include <sys/shm.h> #include <stdio.h> #include <stdlib.h> #define SHMSZ 27 (ζπλέρεηα) main() { int shmid; key_t key; char *shm, *s; /* We need to get the segment named "5678", created by the server. */ key = 5678; /* Locate the segment. */ if ((shmid = shmget(key, SHMSZ, 0666)) < 0) { perror("shmget"); exit(1); } 16-48
Παξάδεηγκα δπν δηεξγαζηώλ πνπ επηθνηλσλνύλ κέζσ θνηλήο κλήκεο (ζπλέρεηα) /* Now we attach the segment to our data space. */ if ((shm = shmat(shmid, NULL, 0)) == (char *) -1) { perror("shmat"); exit(1); } /* Now read what the server put in the memory. */ for (s = shm; *s!= \0'; s++) putchar(*s); putchar('\n'); /* Finally, change the first character of the segment to '*', indicating we have read the segment. */ *shm = '*'; /* detach from the segment: */ if (shmdt(shm) == -1) perror("shmdt"); return(0); } 16-49
Παξάδεηγκα δπν δηεξγαζηώλ πνπ επηθνηλσλνύλ κέζσ θνηλήο κλήκεο (ζπλέρεηα) bash-3.1$ gcc shm_server.c -o shm_server bash-3.1$ gcc shm_client.c -o shm_client Terminal 1 bash-3.1$./shm_server bash-3.1$ Terminal 2 bash-3.1$./shm_client abcdefghijklmnopqrstuvwxyz bash-3.1$ 16-50
εκαηνθόξνη Έναρ ζημαηοθόπορ είναι έναρ μεηπηηήρ πος πποζθέπει ππόζβαζη ζε ένα κοινό ανηικείμενο δεδομένων για πολλαπλέρ διεπγαζίερ. Μεραληζκόο ζπγρξνληζκνύ δηεξγαζηώλ γηα ηελ απνθιεηζηηθή δηαρείξηζε θνηλώλ πόξσλ (π.ρ. θνηλήο κλήκεο). Πξηλ ηελ είζνδν ζε θξίζηκν ηκήκα ηνπ πξνγξάκκαηόο ηεο, κηα δηεξγαζία δεηά ηελ απαηηνύκελε άδεηα από έλα ειεγθηή ζεκαηνθόξν (αλακέλνληαο, αλ ρξεηάδεηαη, κέρξη λα ηεο δνζεί), νπόηε δεζκεύεη ην απαηηνύκελν κέξνο ηνπ πόξνπ πνπ ειέγρεη ν ζεκαηνθόξνο θαη κεηά ηελ έμνδν από ην θξίζηκν ηκήκα απνδεζκεύεη ην δεζκεπκέλν κέξνο ηνπ πόξνπ. Η δέζκεπζε γίλεηαη κε θαηάιιειε κείσζε ηεο ηηκήο ηνπ ζεκαηνθόξνπ θαη ε απνδέζκεπζε κε θαηάιιειε αύμεζε ηεο ηηκήο ηνπ ζεκαηνθόξνπ. 16-51
εκαηνθόξνη (ζπλέρεηα) Δέζκεπζε θνηλνύ πόξνπ από κηα δηεξγαζία: 1. Έιεγρνο ζεκαηνθόξνπ πνπ ειέγρεη ηνλ πόξν. 2. Αλ ε ηηκή ηνπ ζεκαηνθόξνπ είλαη ζεηηθή, ε δηεξγαζία κπνξεί λα ρξεζηκνπνηήζεη ηνλ θνηλό πόξν. Σόηε ε δηεξγαζία κεηώλεη ηελ ηηκή ηνπ ζεκαηνθόξνπ θαηά 1, δειώλνληαο όηη έρεη ρξεζηκνπνηήζεη κηα κνλάδα ηνπ πόξνπ. 3. Αιιηώο, αλ ε ηηκή ηνπ ζεκαηνθόξνπ είλαη 0, ε δηεξγαζία αλακέλεη (sleep) κέρξη ε ηηκή ηνπ ζεκαηνθόξνπ είλαη κεγαιύηεξε από 0. Όηαλ ε δηεξγαζία ξςπνήζει επηζηξέθεη ζην βήκα 1. Απνδέζκεπζε θνηλνύ πόξνπ από κηα δηεξγαζία: 1. Όηαλ κηα δηεξγαζία ηειεηώζεη κε ηνλ θνηλό πόξν, ηόηε ε ηηκή ηνπ ζεκαηνθόξνπ απμάλεηαη θαηά 1. 2. Αλ άιιεο δηεξγαζίεο αλακέλνπλ (κοιμούνηαι), ηόηε ξςπνούν. Ο έιεγρνο ηνπ ζεκαηνθόξνπ θαη νη όπνηεο ιεηηνπξγίεο πξέπεη λα είλαη αηνκηθή δηαδηθαζία. Γη απηό, νη ζεκαηνθόξνη πινπνηνύληαη κέζα ζηνλ ππξήλα. 16-52
εκαηνθόξνη (ζπλέρεηα) Απαίηεζε: #include <sys/sem.h> Μπνξνύκε λα νξίζνπκε έλα ζεκαηνθόξν σο έλα ζύλνιν κηαο ή πεξηζζνηέξσλ ηηκώλ ζεκαηνθόξσλ. Όηαλ δεκηνπξγνύκε έλα ζεκαηνθόξν, πξέπεη λα οπίζοςμε ηον απιθμό ηων ηιμών μέζα ζηο ζύνολο. 16-53
Δνκή πλόινπ εκαηνθόξσλ Ο ππξήλαο δηαηεξεί κηα δνκή κε ηα αθόινπζα κέιε γηα θάζε ζύλνιν ζεκαηνθόξσλ πνπ δεκηνπξγείηαη: /* Data structure describing a set of semaphores. */ struct semid_ds { struct ipc_perm sem_perm; /* operation permission struct */ time_t sem_otime; /* last semop() time */ time_t sem_ctime; /* last time changed by semctl() */ unsigned long int sem_nsems; /* number of semaphores in set */... }; 16-54
Δεκηνπξγία πλόινπ εκαηνθόξσλ Κιήζε ζπζηήκαηνο semget() #include <sys/sem.h> int semget(key_t key, int nsems, int flag); Επηζηξέθεη: πξνζδηνξηζηή ζεκαηνθόξνπ ζε επηηπρία ή -1 ζε πεξίπησζε ιάζνπο Δεκηνπξγία ζπλόινπ ζεκαηνθόξσλ Επηζηξέθεη έλα πξνζδηνξηζηή γηα έλα ζύλνιν από nsems ζεκαηνθόξνπο πνπ αληηζηνηρεί ζην θιεηδί key. ηελ παξάκεηξν flag ηίζεληαη ηα επηζπκεηά δηθαηώκαηα πξνζηαζίαο θαζώο θαη πξόζζεηεο απαηηήζεηο (IPC_CREAT θαη IPC_EXCL, κε ηελ ίδηα ζεκαζία πνπ έρνπλ ζηηο νπξέο κελπκάησλ θαη ζηελ θνηλή κλήκε) ζρεηηθέο κε ηε δεκηνπξγία ηνπ ζπλόινπ ζεκαηνθόξσλ. Εάλ θαινύκε πθηζηάκελν ζύλνιν ζεκαηνθόξσλ, ε παξάκεηξνο nsems ηίζεηαη 0. 16-55
Δεκηνπξγία πλόινπ εκαηνθόξσλ (ζπλέρεηα) Παράδειγμα: /* ID of the semaphore set. */ int sem_set_id_1; int sem_set_id_2; /* create a private semaphore set with one semaphore in it, with access only to the owner. */ sem_set_id_1 = semget(ipc_private, 1, IPC_CREAT 0600); if (sem_set_id_1 == -1) {perror("main: semget"); exit(1);} /* create a semaphore set with key 250, three semaphores in the set, with access only to the owner. */ sem_set_id_2 = semget(250, 3, IPC_CREAT 0600); if (sem_set_id_2 == -1) {perror("main: semget"); exit(1);} 16-56
Χεηξηζκόο πλόινπ εκαηνθόξσλ Κιήζε ζπζηήκαηνο semop() #include <sys/sem.h> int semop(int semid, struct sembuf semoparray[], size_t nops); Επηζηξέθεη 0 ζε πεξίπησζε επηηπρίαο ή -1 ζε πεξίπησζε ιάζνπο Εθηειεί ζην ζύλνιν ζεκαηνθόξσλ, πνπ πξνζδηνξίδνληαη από ηελ παξάκεηξν semid, ηηο ιεηηνπξγίεο πνπ θαζνξίδνληαη ζε έλα πίλαθα κεγέζνπο nops από δνκέο struct sembuf, ην πξώην ζηνηρείν ηνπ νπνίνπ δείρλεη ε παξάκεηξνο semoparray. Η παξάκεηξνο nops νξίδεη ηνλ αξηζκό ησλ ιεηηνπξγηώλ (ζηνηρεία ηνπ πίλαθα). 16-57
Χεηξηζκόο πλόινπ εκαηνθόξσλ (ζπλέρεηα) Η παξάκεηξνο semoparray είλαη έλαο πίλαθαο από ιεηηνπξγίεο ζεκαηνθόξσλ, πνπ αληηπξνζσπεύεηαη από δνκέο sembuf: /* Structure used for argument to `semop' to describe operations. */ struct sembuf { unsigned short int sem_num; /* semaphore number */ short int sem_op; /* semaphore operation */ short int sem_flg; /* operation flag */ }; Πεξηγξάθεη ηε ιεηηνπξγία κεηαβνιήο ηεο ηηκήο ηνπ ππ αξηζκό sem_num ζεκαηνθόξνπ ηνπ ζπλόινπ (από 0 έσο nsems -1) θαηά sem_op (<0 γηα δέζκεπζε θαη >0 γηα απνδέζκεπζε). 16-58
Χεηξηζκόο πλόινπ εκαηνθόξσλ (ζπλέρεηα) SEM_UNDO flag Δεκηνπξγείηαη πξόβιεκα όηαλ κηα δηεξγαζία ηεξκαηίδεηαη, ελώ έρεη πόξνπο δεζκεπκέλνπο δηακέζνπ ελόο ζεκαηνθόξνπ. Όηαλ νξίδνπκε ηε SEM_UNDO flag ζηελ θιήζε ζπζηήκαηνο semop() γηα κηα ιεηηνπξγία ζεκαηνθόξνπ θαη δεζκεύνπκε πόξνπο (κηα sem_op ηηκή <0), ν ππξήλαο ζπκάηαη πόζνπο πόξνπο έρνπκε δεζκεύζεη από ην ζπγθεθξηκέλν ζεκαηνθόξν (ε απόιπηε ηηκή ηνπ sem_op). Όηαλ ε δηεξγαζία ηεξκαηίζεη, ν ππξήλαο ειέγρεη θαηά πόζν ε δηεξγαζία έρεη νπνηεζδήπνηε κε-νινθιεξσκέλεο ξπζκίζεηο ηεο ηηκήο ηνπ ζεκαηνθόξνπ θαη εθαξκόδεη απηέο ηηο ξπζκίζεηο. 16-59
Έιεγρνο εκαηνθόξνπ Κιήζε ζπζηήκαηνο semctl() #include <sem.h> int semctl(int semid, int semnum, int cmd, union semun arg); Επηζηξέθεη ηηκή αλάινγα κε ηελ εληνιή Εθηειεί ηελ ελέξγεηα cmd ζηνλ semnum ζεκαηνθόξν (από 0 έσο nsems -1) ηνπ ζπλόινπ ζεκαηνθόξσλ (ή αλάινγα κε ηελ εληνιή, ζε νιόθιεξν ην ζύλνιν) πνπ αληηζηνηρεί ζηνλ πξνζδηνξηζηή semid Η έλσζε union semun είλαη νξηζκέλε σο /* The user should define a union like the following to use it for arguments for `semctl'. */ 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 */ }; 16-60
Έιεγρνο εκαηνθόξνπ (ζπλέρεηα) Με ηελ εληνιή IPC_STAT ζπκπιεξώλνληαη ηα πεδία ηεο δνκήο *(arg.buf) κε ηα ραξαθηεξηζηηθά ηνπ ζπλόινπ ζεκαηνθόξσλ. Με ηηο εληνιέο SETVAL θαη GETVAL ηίζεηαη ζαλ ηηκή ελόο ζεκαηνθόξνπ ην arg.val ή επηζηξέθεη ε θιήζε ζπλάξηεζεο semctl() ηελ ηηκή ηνπ, αληίζηνηρα. Με ηηο εληνιέο SETALL θαη GETALL ηίζεληαη ηηκέο ζηνπο ζεκαηνθόξνπο ηνπ ζπλόινπ (από ηνλ πίλαθα, ζηελ αξρή ηνπ νπνίνπ δείρλεη ην arg.array) ή επηζηξέθνληαη νη ηηκέο ησλ ζεκαηνθόξσλ (ζηνλ πίλαθα arg.array), αληίζηνηρα. Με ηελ εληνιή IPC_RMID θαηαζηξέθεηαη ην ζύλνιν ησλ ζεκαηνθόξσλ. 16-61
Παξάδεηγκα Παξάδεηγκα επηθνηλσλίαο δπν δηεξγαζηώλ κεηαμύ ηνπο κέζσ θνηλήο κλήκεο θαη ην ζπγρξνληζκό ηνπο κέζσ ζεκαηνθόξσλ /* File: shm_sem_server.c */ #include <sys/types.h> /* For System V IPC */ #include <sys/ipc.h> /* For System V IPC */ #include <sys/shm.h> /* For shared memory */ #include <sys/sem.h> /* For semaphores */ #include <stdio.h> /* For I/O */ #define SHMKEY (key_t)4321 /* Key value of shared memory */ #define SEMKEY (key_t)9876 /* Key value of semaphore set */ #define SHMSIZ 256 /* Size of shared memory */ #define PERMS 0600 /* Permissions of shared memory and semaphore set */ union semun { /* Union for semaphores */ int val; struct semid_ds *buff; unsigned short *array; }; 16-62
Παξάδεηγκα (ζπλέρεηα) main() { int shmid, semid; char line[128], *shmem; struct sembuf oper[1] = {0, 1, 0}; /*want to release shared memory region*/ union semun arg; /* Create shared memory */ if ((shmid = shmget(shmkey, SHMSIZ, PERMS IPC_CREAT)) < 0) { perror("shmget"); exit(1); } printf("created shared memory region with identifier %d\n", shmid); /* Create semaphore set with 1 item */ if ((semid = semget(semkey, 1, PERMS IPC_CREAT)) < 0) { perror("semget"); exit(1); } printf("created semaphore with identifier %d\n", semid); /* Initialize semaphore for locking */ arg.val=0; if (semctl(semid, 0, SETVAL, arg) < 0) { perror("semctl"); exit(1); } printf("initialized semaphore to lock shared memory region\n"); 16-63
Παξάδεηγκα (ζπλέρεηα) /* Attach shared memory region locally */ if ((shmem = shmat(shmid, (char *) 0, 0)) == (char *) -1) { perror("shmat"); exit(1); } printf("attached shared memory region\n"); /* Write message to shared memory */ printf("give input line: "); fgets(line, sizeof line, stdin); line[strlen(line)-1] = '\0'; strcpy(shmem, line); printf("wrote to shared memory region: %s\n", line); /* Make shared memory available */ if (semop(semid, &oper[0], 1) < 0) { perror("semop"); exit(1); } printf("released shared memory region\n"); } 16-64
Παξάδεηγκα (ζπλέρεηα) /* File: shm_sem_client.c */ #include <sys/types.h> /* For System V IPC */ #include <sys/ipc.h> /* For System V IPC */ #include <sys/shm.h> /* For shared memory */ #include <sys/sem.h> /* For semaphores */ #include <stdio.h> /* For I/O */ #define SHMKEY (key_t)4321 /* Key value of shared memory */ #define SEMKEY (key_t)9876 /* Key value of semaphore set */ #define SHMSIZ 256 /* Size of shared memory */ #define PERMS 0600 /* Permissions of shared memory and semaphore set */ main() { int shmid, semid; char *shmem; struct sembuf oper[1] = {0, -1, 0}; /*want to reserve shared memory region*/ 16-65
Παξάδεηγκα (ζπλέρεηα) /* Access shared memory */ if ((shmid = shmget(shmkey, SHMSIZ, PERMS)) < 0) { perror("shmget"); exit(1); } printf("accessing shared memory region with identifier %d\n", shmid); /* Access semaphore set */ if ((semid = semget(semkey, 1, PERMS)) < 0) { perror("semget"); exit(1); } printf("accessing semaphore with identifier %d\n", semid); /* Attach shared memory region locally */ if ((shmem = shmat(shmid, (char *) 0, 0)) == (char *) -1) { perror("shmat"); exit(1); } printf("attached shared memory region\n"); 16-66
Παξάδεηγκα (ζπλέρεηα) printf("asking for access to shared memory region\n"); /* Ask if you may access shared memory */ if (semop(semid, &oper[0], 1) < 0) { perror("semop"); exit(1); } printf("read from shared memory region: %s\n", shmem); /* Accessing */ /* Destroy shared memory */ if (shmctl(shmid, IPC_RMID, (struct shmid_ds *) 0) < 0) { perror("shmctl"); exit(1); } printf("removed shared memory region with identifier %d\n", shmid); /* Destroy semaphore set */ if (semctl(semid, 0, IPC_RMID, 0) < 0) { perror("semctl"); exit(1); } printf("removed semaphore with identifier %d\n", semid); } 16-67
Παξάδεηγκα (ζπλέρεηα) bash-3.1$ gcc shm_sem_server.c -o shm_sem_server bash-3.1$ gcc shm_sem_client.c -o shm_sem_client bash-3.1$./shm_sem_server Created shared memory region with identifier 6946821 Created semaphore with identifier 327680 Initialized semaphore to lock shared memory region Attached shared memory region Give input line: To be saved in shared memory Wrote to shared memory region: To be saved in shared memory Released shared memory region bash-3.1$ bash-3.1$./shm_sem_client Accessing shared memory region with identifier 6946821 Accessing semaphore with identifier 327680 Attached shared memory region Asking for access to shared memory region Read from shared memory region: To be saved in shared memory Removed shared memory region with identifier 6946821 Removed semaphore with identifier 327680 bash-3.1$ 16-68