1 / 41

מערכות הפעלה

מערכות הפעלה. תרגול 4 – ניהול תהליכים, מבני נתונים למימוש תהליכים. מה בתכנית?. ניהול תהליכים מימוש תהליכים ב- XINU טבלת תהליכים מימוש תורי תהליכים תרגילים. ניהול תהליכים. המעבד מריץ את כל התהליכים אך בכל רגע נתון הוא מריץ תהליך בודד

eman
Download Presentation

מערכות הפעלה

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. מערכות הפעלה תרגול 4 – ניהול תהליכים, מבני נתונים למימוש תהליכים

  2. מה בתכנית? • ניהול תהליכים • מימוש תהליכים ב-XINU • טבלת תהליכים • מימוש תורי תהליכים • תרגילים

  3. ניהול תהליכים • המעבד מריץ את כל התהליכים אך בכל רגע נתון הוא מריץ תהליך בודד • התהליך המורץ במעבד נקרא תהליך נוכחי (current process) • תהליכים אחרים מחכים לביצוע במעבד, או מחכים לקבלת משאב אחר

  4. ניהול תהליכים • מערכת ההפעלה אחראית על כך שבכל רגע ורגע יהיה תהליך אחד מוגדר כתהליך הנוכחי • במידה והתהליך מוותר על מעמדו כתהליך הנוכחי או שמערכת ההפעלה מחליטה להחליפו, עליה לבחור תהליך אחר שיחליף אותו

  5. ניהול תהליכים • האלגוריתם המחליט האם להחליף את התהליך הנוכחי ומי התהליך שיחליפו נקרא זמן (Scheduler) • בזמן החלפת התהליך הנוכחי יש לשמור את ההקשר שלו (context) (הכולל את ערכי הרגיסטרים שונים) כדי שניתן יהיה לשחזר אותו בזמן החזרתו לביצוע (החלפת הקשר, Context Switching)

  6. מדיניות הזימון • התהליך הנוכחי נבחר בין תהליכים המחכים למעבד • קיימות כמה שיטות לבחירת התהליך הנוכחי: • מדיניות FIFO • בחירה סדרתית (Round-Robin) • בחירה לפי עדיפות • בחירה לפי זמן ריצה

  7. First Come First Serve (or FIFO) • במקור, תהליך אחד משתמש במעבד עד לסיומו • כיום, תהליך משתמש במעבד עד שנחסם בהמתנה למאורע כלשהו • מדיניות ללא הפקעה (non-preemptive) תהליכים קצרים "נתקעים" אחרי תהליכים ארוכים => תהליכים קצרים נמצאים הרבה זמן בתור המוכנים, יחסית לזמן החישוב שהם צורכים

  8. Round-Robin • כל תהליך מקבל את המעבד לפרק זמן קצוב, ולאחריו הוא מוחלף באחר אף אם לא סיים. ההחלפה נעשית לפי סדר קבוע (Round-Robin) • חלוקת זמן בין התהליכים השונים הוגנת • דוגמה: נוכחי

  9. מדיניות הזימון • לפי עדיפות: לכל תהליך משוייך מספר עדיפות. התהליך בעל עדיפות גבוהה ביותר המחכה למעבד הופך לתהליך הנוכחי • סדר העדיפויות: 1 6 8 9 10 13

  10. מדיניות הזימון לפי עדיפות • התהליך הנוכחי יאבד את המעבד רק אם תהליך בעל עדיפות גבוהה יותר ידרוש אותו, או עם יוותר עליו בעצמו • אם תהליך בעל עדיפות גבוהה יותר לא ישחרר את המעבד, תהליכים בעלי עדיפות נמוכה יותר לא יתבצעו • קיימות מ"ה בהן תהליך שמתבצע מאבד את עדיפותו עם הזמן, ותהליך שמחכה משפר את עדיפותו כדי לאפשר "צדק" גדול יותר בחלוקת משאב המעבד

  11. מדיניות הזימון – היישום ב-XINU • XINU משתמשת בשיטת העדיפויות כאשר בין התהליכים באותה עדיפות מתבצע Round-Robin • העדיפות של תהליך נקבעת בזמן יצירתו, אך ניתנת לשינוי בכל עת.

  12. תהליך - דיאגרמת מצבים send receive RECEIVING wait signal WAITING sleep wake up SLEEPING resched resched CURRENT READY SUSPENDED suspend suspend resume Create

  13. טבלת תהליכים • קיימת טבלת תהליכים, המיוצגת כוקטור של רשומות, בה כל רשומה מייצגת הקשר של תהליך, ולכל תהליך מוקצת רשומה • רשומה מכילה את המידע על מצב התהליך ואת כל המידע על הקשר התהליך הדרוש להפעלתו • קיימים מספר משתנים המייצגים את מצב התהליך או שמציינים שתהליך מחכה למשאב כלשהו

  14. טבלת תהליכים - המשך • האינדקס בטבלת התהליכים משמש כמזהה של התהליך (pid – process identifier) • המזהה של התהליך הנוכחי שמור במשתנה נפרד המאפשר התיחסות לתהליך הנוכחי מקוד מ"ה • התהליכים המחכים למעבד שמורים בתור דו-כווני על פי עדיפותם. תור זה נקרא ready queue ומבוצע על ידי rdyhead, rdytail

  15. טבלת תהליכיםproc.h - #define NULLPROC 0 /* id of the null process; it */ /* is always eligible to run */ extern struct pentry proctab[]; extern int numproc; /* currently active processes */ extern int nextproc; /* search point for free slot */ extern int currpid; /* currently executing process */

  16. טבלת תהליכיםproc.h - /* process table entry */ struct pentry { char pstate; /* process state: PRCURR, etc. */ int pprio; /* process priority */ int psem; /* semaphore if process waiting */ int pmsg; /* message sent to this process */ int phasmsg; /* nonzero iff pmsg is valid */ char *pregs; /* saved environment */ char *pbase; /* base of run time stack */ word plen; /* stack length in bytes */ char pname[PNMLEN+1]; /* process name */ int pargs; /* initial number of arguments */ int (*paddr)(); /* initial code address */ };

  17. טבלת תהליכיםproc.h - #defineNPROC 30 /* process state constants */ #definePRCURR '\01' // process is currently running #definePRFREE '\02' // process slot is free #definePRREADY '\03' // process is on ready queue #definePRRECV '\04' // process waiting for message #definePRSLEEP '\05' // process is sleeping #definePRSUSP '\06' // process is suspended #definePRWAIT '\07' // process is on semaphore queue

  18. תהליך ה-NULL מה עושה מ"ה כאשר אין תהליך הדורש מעבד? • אחת הדרכים האפשריות היא לתת לזמן לבצע לולאה ולחכות עד שתהליך כלשהו יהיה מוכן לחזור לביצוע אך לשם כך שקוד הזמן יהיה מורכב יותר • דרך מועדפת הינה ליצור תהליך שתמיד יהיה מוכן לחישוב

  19. תהליך ה-NULL - המשך • תהליך זה נקרא NULL process ובנוי כלולאה אינסופית מהצורה While (TRUE) /* Do nothing */; • תהליך ה-NULL יקבל את העדיפות המזערית האפשרית ולכן יהפך לנוכחי רק כאשר אין אף תהליך אחר שדורש את המעבד • המזהה של תהליך זה הוא 0

  20. רשימות תהליכים ב-XINU • במהלך הריצה, בכל רגע, חלק ניכר מתהליכים נמצאים במצב המתנה למשאבים (CPU, קלט, הודעה וכו') • מכיוון שמספר תהליכים עלולים להמתין לאותו משאב יש לנהל תור המתנה • כלל: התהליך יכול להופיע בכל זמן נתון בתור אחד • מספר התהליכים והתורים השונים הוא סופי

  21. מימוש הרשימות • בעיה: הרשימות הנחוצים עבור המשאבים השונים הם מגוונים (FIFO,לפי עדיפות, תור הפרשים) עובדה זו מקשה על ניהול מערכת הרשימות • פתרון: מבנה אחיד לכל הרשימות שמספק את כל מגוון הדרישות ומאפשר אחידות בטיפול

  22. מבנה רשומה • qprev -מצביע האיבר הבא • qnext -מצביע האיבר הקודם • qkey -מפתח, עדיפות של התהליך

  23. הגדרת תור – q.h מבנה רשומה: struct qent { int qkey; int qnext; int qprev; };

  24. תורים ב-XINU • תור התהליכים המחכים למעבד • תור עדיפויות, הכנסה לפי מפתח – עדיפות • בתור עדיפויות התהליכים מסודרים בסדר עולה בכיוון ראש => זנב • הוצאה – איבר אחרון • תור התהליכים המחכים לסמפור – FIFO • הוצאה – מראש התור • תור הרדומים – תור ההפרשים

  25. מימוש רשימהבעזרת מערך Key Next Prev 0 25 33 3 1 2 NPROC 140 32 3 ... איבר קודם NPROC-1 איבר הבא NPROC ... 2NSEM+4 Head=32 MININT 3 -1 Tail=33 MAXINT -1 1

  26. הגדרת תור – q.h Inline list manipulation procedures extern struct qent q[]; #define isempty(list) (q[(list)].qnext >= NPROC) #define nonempty(list) (q[(list)].qnext < NPROC) #define firstkey(list) (q[q[(list)].qnext].qkey) #define lastkey(tail) (q[q[(tail)].qprev].qkey) #define firstid(list) (q[(list)].qnext)

  27. פונקציות לטיפול ברשימות • enqueueהכנסת איבר לסוף הרשימה • dequeueניתוק איבר מהרשימה והחזרת האינדקס שלו • insertהכנסת תהליך לרשימה לפי ערכו של key • getfirstהסרת התהליך הראשון ברשימה והחזרת האינדקס • getlast הסרת התהליך האחרון ברשימה והחזרת האינדקס • newqueueאיתחול רשימה חדשה במבנה ה-q

  28. הכנסה לפי מפתח – insert.c #include <conf.h> #include <kernel.h> #include <q.h> int insert(proc, head, key) int proc; /* process to insert */ int head; /* q index of head of list */ int key; /* key to use for this process */ { int next; /* runs through list */ int prev; next = q[head].qnext; while (q[next].qkey < key) /* tail key is MAXINT */ next = q[next].qnext; q[proc].qnext = next; q[proc].qprev = prev = q[next].qprev; q[proc].qkey = key; q[prev].qnext = proc; q[next].qprev = proc; return(OK); }

  29. הוספה לסוף התור – queue.c #include <conf.h> #include <kernel.h> #include <q.h> int enqueue(item, tail) int item; int tail; { structqent *tptr; /* tail entry */ structqent *mptr; /* item entry */ tptr = &q[tail]; mptr = &q[item]; mptr->qnext = tail; mptr->qprev = tptr->qprev; q[tptr->qprev].qnext = item; tptr->qprev = item; return(item); }

  30. הוצאה מתור – queue.c #include <conf.h> #include <kernel.h> #include <q.h> int dequeue(item) int item; { struct qent *mptr; /* q entry for item */ mptr = &q[item]; q[mptr->qprev].qnext = mptr->qnext; q[mptr->qnext].qprev = mptr->qprev; return(item); }

  31. הסרת התהליך הראשון ברשימה – getitem.c #include <conf.h> #include <kernel.h> #include <q.h> int getfirst(head) int head; /* q index of head of list */ { int proc; /* first process on the list */ if ((proc=q[head].qnext) < NPROC) return( dequeue(proc) ); else return(EMPTY); }

  32. הסרת התהליך האחרון ברשימה – getitem.c #include <conf.h> #include <kernel.h> #include <q.h> int getlast(tail) int tail;/* q index of tail of list */ { int proc;/* last process on the list*/ if ((proc=q[tail].qprev) < NPROC) return( dequeue(proc) ); else return(EMPTY); }

  33. איתחול רשימה חדשה – newqueue.c int newqueue() { struct qent *hptr; /* address of new list head */ struct qent *tptr; /* address of new list tail */ int hindex, tindex; /* head and tail indexes */ /* nextqueue is global variable */ hptr = &q[ hindex=nextqueue++ ]; /* giving next used q pos. */ tptr = &q[ tindex=nextqueue++ ]; hptr->qnext = tindex; hptr->qprev = EMPTY; hptr->qkey = MININT; tptr->qnext = EMPTY; tptr->qprev = hindex; tptr->qkey = MAXINT; return(hindex); }

  34. טבלת תהליכים/ תורים יישום התורים של התהליכים מתבצע על ידי פונקציות ניהול תורים לכן: • אין בטבלת תהליכים מצביעים על סדר התורים • ניהול התורים נעשה בטבלת התורים (q) • לכל תהליך משוייכת רשומה בטבלת תהליכים וכן בטבלת התורים

  35. טבלת תהליכים/ תורים • בטבלת התורים יש יותר רשומות מטבלת התהליכים.NPROC רשומות ראשונות בטבלת התורים משויכות לתהליכים המקבילים בטבלת התהליכים. • שאר הרשומות בטבלת התורים משמשות כראשי/זנבות תורים שונים (Ready ,סמפורים, וכו')

  36. תרגיל 1 • נתון: • קיימים שני תהליכים • תהליך ראשון מעלה את המונה ב-1 • מטרה: • על התהליך השני להדפיס את ערך המונה בכל פעם שמתבצעת החלפת התהליכים במעבד

  37. פתרון unsigned long int who_is_current = 0, count = 0; xmain() { int Inc(), Pr(); resume( create(Inc, INITSTK, INITPRIO, "proc 1", 0)); resume( create(Pr, INITSTK, INITPRIO, "proc 2", 0)); while(1) ; // Do nothing but serve as alternative to Inc // Pr may not be ready (printing) }

  38. פתרון – המשך 1 Inc() { int mypid; mypid = getpid(); /* Store my pid */ while (1) { count = 0; who_is_current = mypid; /* Signal I am current */ /* As long as I am current, increment count */ while(who_is_current == mypid) count++; /* I have been replaced and become current again */ } /* while */ } /* Inc */

  39. פתרון – המשך 2 Pr() { char str[80]; int count_value; int mypid; mypid = getpid(); while(1) { count_value = count; /* Store count value aside, locally */ who_is_current = mypid; /* Signal I am current */ sprintf(str, "count_value = %lu\n", count_value); printf(str); while (who_is_current == mypid) /* Do not continue until */ ; /* I am replaced and current again */ } /* while */ } /* Pr */

  40. תרגיל 2 יש למלא את המבנה של Q כפי שהוא נראה ברגע שהתכנית הגיע אל הנקודה המסומנת ב- /**/ #include <kernel.h> extern SYSCALL sleep(), wait(); int nop(); xmain() { int sem = screate(1); resume(create(sleep, INITSTK, 20, “pr1”, 1, 25)); resume(create(wait, INITSTK, 22, “pr2”, 1, sem)); resume(create(wait, INITSTK, 24, “pr3”, 1, sem)); resume(create(sleep, INITSTK, 21, “pr4”, 1, 10)); resume(create(nop, INITSTK, 20, “pr5”, 0)); resume(create(sleep, INITSTK, 20, “pr6”, 1, 30)); resume(create(wait, INITSTK, 20, “pr7”, 1, sem)); resume(create(nop, INITSTK, 20, “pr8”, 0)); create(sleep, INITSTK, 33, “pr9”, 1, 44); /**/ nop(); } nop() { while(1){}; }

  41. תרגיל 3 pr3 pr7 SEM pr4 (10) pr1 (15) pr6 (5) SLEEP pr5 (20) 1 2 pr8 (20) READY

More Related