ריבוי יישומים – Multitasking

ריבוי יישומים Multitasking – מאת גיל טופמן

 

Multitasking - הרצת כמה יישומים בו זמנית.

 

לרוב אנו משתמשים במעבד אחד בלבד, ולכן כיצד ניתן להפעיל כמה יישומים בו זמנית?

בכדי להפעיל כמה יישומים בו זמנית הקוד שלהם אינו חייב דווקא לרוץ באותו הזמן.

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

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

ניתן להעזר בפסיקת גלישה (Overflow) של השעון, ובכל פסיקה להשתמש כיחידת זמן אטומית אחת.

 

מכיוון שלרוב אנו לא יכולים לצפות מראש את מספר היישומים שירוצו, אם נבחר כזמן המעבד 10 יחידות זמן

לא יוכלו לרוץ יותר מ-10 ישומים. כדי להתגבר על בעיה זו, נגדיר את זמן המעבד כ-n  = מספר היישומים.

כך נחליף בכל יחידת זמן את הישום הפועל לישום הבא אחריו וכשנגיע אל היישום האחרון נחזור אל הראשון.

 

עד כאן הכל פשוט ויפה, אך הבה נתקדם צעד אחד אל המציאות ונזכר כי המעבד נעזר במחסנית (stack), ולכל יישום יש לספק stack  משלו על מנת לשמור על רציפות המערכת. כדי לעשות זאת נצטרך לבנות מערכת המתחזקת את היישומים הרצים, ואת הזיכרון בו הם משתמשים. נגדיר חלק מהזיכרון אשר יוקצה באופן קבוע ל-stack, אותו נחלק ליחידות אטומיות. כדי ליצור יישום חדש אנו נקרא לפונקציה מיוחדת אשר תקצה מקום ל-stack לכל יישום ושתכניס אותו ללולאת היישומים. למעשה אנו ע"י הקצאת הזיכרון אנו קובעים תקרה למספר הישומים המקסימלי שניתן להפעיל בו זמנית. לכל ישום אנו מקצים מספר בלוקים של זיכרון, שיספיקו לו לצורך פעולה תקינה.

 

 

לכל יישום יהיה מבנה נתונים בסגנון הבא:

struct Task {

        int         FirstStartBlock;

        int         BlocksAllocated;

        void      *StackPointer;

};

 

הנתון FirstStartBlock מכיל את המספר הסידורי של הבלוק הראשון של הזכרון בו משתמש היישום, והנתון BlocksAllocated מכיל את מספר הבלוקים (הרציפים) המוקצים ליישום. *Stackpointer הוא, כמובן, מצביע המחסנית. הפונקציה אשר תריץ יישומים חדשים תשתמש במערך של היישומים הפעילים ותתחזק אותם ביחד עם ה-stack.

 

בואו נתקדם עוד צעד יותר, ונגלה כי כפי שאסור לנו לפגוע ב-stack, עלינו גם לדאוג שהאוגרים (Registers) יחזרו עם אותם הערכים. האפשרות הטבעית היא לשמור על ה-stack  בנוסף לנתונים גם את ערכי האוגרים. אך אם נשים לב אנו רוצים לממש את החלפת היישום בתוך פסיקת הזמן. ברוב המעבדים, הפסיקה שומרת את ערכי האוגרים ב-stack  בזמן הקריאה לה, ומחזירה אותם בסיום -  לכן כל מה שעלינו לבצע זה החלפת כתובת ה-stack. המתכנת אינו אמור לדאוג לשמירת האוגרים.

 

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

 

הקוד של הפסיקה יראה כך:

 

פסיקת הזמן

X. שמירה אוטומטית של מצביע הקוד בו הפסקנו.

X. שמירה אוטומטית של ערכי האוגרים.

1.שמור את מצביע ה-stack  ב StackPointer* של היישום הנוכחי.

2. השג את מבנה הנתונים של היישום הבא.

3. הכנס את StackPointer* ששמרנו מראש למצביע ה-stack.

X. שיחזור אוטומטי של ערכי האוגרים

X. חזרה אוטומטית אל הקוד בו הפסקנו.

(X) - שלב המבוצע אוטומטית ע"י המעבד ללא פקודות מיוחדות.

 

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

 

יש כמובן צורך לממש את כל הפונקציות המתחילות ומסיימות יישום, ואת הפרטים האלו אשאיר למתכנת הנבון. כאשר מפעילים יישום חדש, יש לזכור לאתחל את ה-stack ואת המצביע כך שכתובת התחלת היישום תופיע ככתובת חזרה של הפסיקה.

חזרה




יש לך שאלה ואין לך את מי לשאול? פורום הרובוטיקה לעזרתך!

,בעלי אתר זה לא ישאו באחריות כלשהי לכל נזק, כספי או אחר
שייגרם במישרין או בעקיפין משימוש במידע המצוי באתר זה

כל הזכויות שמורות לאסף פוניס, גיא יונה ואלי קולברג ©
אין להעתיק תכנים מאתר זה ללא רשות בכתב ממנהלי האתר

אתר זה נצפה באופן מיטבי ברזולוציית 1024X768