יום ראשון

IPC: Shared Memory

הפוסט הזה מדגים  מנגנון נוסף למימוש-IPC. ה- Shared Memory הוא איזור זיכרון משותף בין processes. 
המנגנון פשוט מאד, ונמחיש אותו בדוגמא. הדוגמא יוצרת סיגמנט של shared memory בגודל 1k, ומדגימה כתיבה אליו וקריאה ממנו.
מה התוכנית כותבת לזיכרון המשותף? היא מעתיקה לזיכרון את המחרוזת שבתוך [argv[1 - הארגומנט של פקודת ההרצה.
איך גורמים לתוכנית לקרוא מהזיכרון המשותף? מפעילים אותה בלי ארגומנט. היא  תקרא את תוכן ה-shared memory ותוציא אותו לפלט.
איך לחסל את סיגמנט הזיכרון? ע"י הרצת התוכנית עם הארגומנט "d".

גם את הדוגמא הזאת לקחתי מתוך - Beej's Guide to Unix IPC.  (אפשר היה בקלות לחבר דוגמא אחרת, אבל אני רוצה לתת ל-Beej  קרדיטים על העבודה הטובה שלו. מגיע לו). בכל אופן, הכנסתי שינויים קלים בלבד.


נראה פעולה של 4 פונקציות - מודגשות בצהוב בתוכנית:
1. shmget - יצירת סיגמנט הזיכרון\קבלת מזהה הגישה לזיכרון. 
2. shmat - פעולת attach לזיכרון.
3. shmdt - פעולת detach.n. פעולת ה-detach לא מסירה לגמרי את הזיכרון.
4. הסרת הזיכרון  עם: shmctl


את התוכנית אפשר להריץ ב-3 אופנים:
- עם ארגומנט, והוא יכתב ל-shared memory. לדוגמא:
"mmapdem "copy this

-ללא ארגומנט, ואז תוכן ה-shared memory ישלח ל-output

mmapdem
-עם הארגומנט "d", שיגרום להסרת הזיכרון:
mmapdem "d"

ההסרה נעשית בעזרת הפונקציה:
shmctl(shmid, IPC_RMID, NULL);







הנה הדוגמא:

  1. /*
  2.  * mmapdemo.c
  3.  *
  4.  *  Created on: May 13, 2012
  5.  */
  6. #include <stdio.h>
  7. #include <stdlib.h>
  8. #include <string.h>
  9. #include <sys/types.h>
  10. #include <sys/ipc.h>
  11. #include <sys/shm.h>
  12. #define SHM_SIZE 1024 /* make it a 1K shared memory segment */
  13. int main(int argc, char *argv[])
  14. {
  15. key_t key;
  16. int shmid;
  17. char *data;
  18. if (argc > 2) {
  19. fprintf(stderr, "usage: shmdemo [data_to_write]\n");
  20. exit(1);
  21. }
  22. /* make the key: */
  23. if ((key = ftok("/tmp", 'R')) == -1) {
  24. perror("ftok");
  25. exit(1);
  26. }
  27. /* connect to (and possibly create) the segment: */
  28. if ((shmid = shmget(key, SHM_SIZE, 0644 | IPC_CREAT)) == -1) {
  29. perror("shmget");
  30. exit(1);
  31. }
  32. /* attach to the segment to get a pointer to it: */
  33. data = shmat(shmid, (void *)0, 0);
  34. if (data == (char *)(-1)) {
  35. perror("shmat");
  36. exit(1);
  37. }
  38. /* read or modify the segment, based on the command line: */
  39. if (argc == 2) {
  40. if('d' == *argv[1]){ /* remove */
  41. printf("Removing segment\n");
  42. shmctl(shmid, IPC_RMID, NULL);
  43. }
  44. else{
  45. printf("writing to segment: \"%s\"\n", argv[1]);
  46. strncpy(data, argv[1], SHM_SIZE);
  47. }
  48. } else
  49. printf("segment contains: \"%s\"\n", data);
  50. /* detach from the segment: */
  51. if (shmdt(data) == -1) {
  52. perror("shmdt");
  53. exit(1);
  54. }
  55. return 0;
  56. }


נעקוב כאן אחרי 4 הפונקציות העיקריות (הזכרנו אותן למעלה והן מסומנות בצהוב):
1. שורה 28 : 
shmget
הפונקציה מחזירה מזהה לסיגמנט הזיכרון. נשתמש במזהה אחכ.

הנה ה-prototype:

int shmget(key_t key, size_t size, int shmflg);

הפונקציה מקבלת שלושה פרמטרים:
key - מזהה יחודי (unique). כל המשתמשים בסיגמנט הזה חייבים להשתמש באותו key. השתמשנו בפונקציית העזר  ftok שמייצרת את ה-key  בהנתן שם קובץ ו-integer (שורה 23). בפוסט על msg queue יצרנו key באופן דומה, כך שניתן למצוא הסבר נוסף לתהליך שם.
size - גודל הסיגמנט. אצלנו הגודל הוא 1k.
flags - בדומה למה שראינו ב-msg queue - ה-flags מורכב משני מרכיבים:-permission ו-flags.... אצלנו ה-permission הוא 644. הקידוד של ה-permission זהה ל-permission של קבצים בלינוקס, כך שהמשמעות של 644 היא - הרשאת כתיבה_וקריאה ל-owner, ועבור השאר קריאה בלבד. הדגל הנוסף - IPC_CREAT גורם ליצירת הסיגמנט. אם הסיגמנט כבר קיים, לא יקרה שום נזק.


2. שורה 33shmat. ביצוע attachment בין ה-pointer לבין ההזיכרון.
הנה ה-prototype:

void *shmat(int shmid, void *shmaddr, int shmflg);

מקבלת 3 פרמטרים:
shmid - זה המזהה שהתקבל מ-shmget.
shemaddr - כתובת של הסיגמנט. הערך 0 יגרום למערכת לקבוע את המיקום בעצמה. כך נפעל בדוגמא.
shmflg - אפשר לקבוע את ה-flag כ-SHM_RDONLY, ולחסום אפשרות כתיבה. אצלנו הshmflg הוא 0 - אין מגבלת כתיבה.

shmat מחזירה pointer ל- shared memory segment שנוצר- או בקיצור - את הכתובת. 




3. שורה 42shmctl. מוחקת את הסיגמנט, עם הדגל IPC_RMID.
עפ"י שורה 40 - הפונקציה הזו תופעל רק אם נריץ את  mmapdem עם "d".


4. שורה 51shmdt. מבצעת detach לסיגמנט הזיכרון.
ה-prototype:
int shmdt(void *shmaddr);

shmaddr - הכתובת של הסיגמנט - התקבלה בפקודת ה-attach.



סקרנו את 4 ה-API של ה-shared memory.
נשלים את התמונה עם מבט על הכתיבה לזיכרון המשותף והקריאה ממנו.

הכתיבה מתבצעת בשורה 46:
strncpy(data, argv[1], SHM_SIZE);
פשוט העתקה ל-data שמצביע על תחילת סיגמנט הזיכרון.

הקריאה - שורה 49 - גישה פשוטה לזיכרון בעזרת המצביע data:
printf("segment contains: \"%s\"\n", data);

==סוף ==

אין תגובות:

הוסף רשומת תגובה