שבוע #13-14 פרקProcess Synchronization : סינכרון בין תהליכים חלק א' קורס מערכות הפעלה א' מכללת הדסה /מכללה חרדית צבי מלמד [email protected] הרצאות הקורס מבוססות במידה רבה ביותר על ההרצאות של ד"ר יורם ביברמן © כל הזכויות שמורות לד"ר יורם ביברמן ולצבי מלמד ©צבי מלמד 1 a cooperating process • תהליך משתף-פעולה )(a cooperating process – תהליך שעשוי להשפיע או להיות מושפע מתהליכים אחרים במערכת. – עשוי לחלוק מרחב כתובות )בפרט נתונים( עם אחרים – עשוי להעביר מידע דרך ערוצי תקשורת עם עמיתים. • בפרק זה ,כשנדבר על תהליך אנו נתכוון גם לפתיל – שיתוף נתונים עם פתילים אחרים רלבנטי במיוחד לגבי פתילים ©צבי מלמד 2 רקע Background • תיפעול זוג תהליכים :יצרן וצרכן – מעבירים זה לזה הודעות – באמצעות זיכרון משותף המנוהל כתור – מימוש במערך מעגלי בגודל BUFFER_SIZEתאים • אופן הפעולה: – היצרן מוסיף איברים לתור ,והצרכן גורע. • משתני עזר: – מונה ) (counterהמציין כמה איברים מצויים בתור בכל נקודת זמן .היצרן מגדיל את המונה ,הצרכן מקטין. – המשתנה inמציין לאן מכניס היצרן את האיבר הבא, – המשתנה outיציין מהיכן יצרוך הצרכן את האיבר הבא. – in, outמאותחלים לאפס. ©צבי מלמד 3 מבוא )דוגמא( – קוד היצרן • תיאום: – כאשר התור מלא על היצרן להמתין ,כאשר התור ריק על הצרכן להמתין. • קוד היצרן: { )while (1 while (counter == BUFFER_SIZE) ; // busy wait ; buffer[in] = new_item ; in = (in +1) % BUFFER_SIZE ; counter++ } ©צבי מלמד 4 מבוא )דוגמא( – קוד הצרכן :• קוד הצרכן סימטרי while (1) { while (counter == 0) ; //busy wait new_item = buffer[out] ; out = (out +1) % BUFFER_SIZE ; counter-- ; } 5 ©צבי מלמד דוגמת מבוא – תיזמון אפשרי ותוצאתו • עתה נניח שהתור מכיל 17פריטים. היצרן והצרכן פונים אליו במקביל, בפרט מתפעלים במקביל את :counter האחד מגדיל את ערכו ,השני מקטינו. • נניח שמערכת ההפעלה מתזמנת את הפעולות באופן הבא )תוך שהמעבד מבצע לסירוגין כל תהליך( התוצאה :ערכו של המונה הוא 16 )ולא 17כפי שראוי(. הסיבה :שני התהליכים פנו למשתנה המשותף במקביל ,ותפעלו אותו באופן לא מתואם\מסונכרן צרכן יצרן reg1 = counter )(reg117 reg2 = counter )(reg217 reg1++ )(reg118 reg2-)(reg216 counter = reg1 )(counter18 counter = reg2 )(counter16 ©צבי מלמד 6 מבוא )המשך( • תקלה דומה אך שונה: – עדכונו של המשתנה )על-פי ערכו של אוגר מתאים( ע"י תהליך א' לוקח יותר ממחזור זיכרון יחיד – בין תחילת העדכון לסיומו מתעניין תהליך ב' בערכו של המשתנה ,ועל כן מקבל ערך שגוי. ©צבי מלמד 7 מצבי מירוץ Race Condition - • מצבי מרוץ ) :(race conditionמצב שבו התוצאה תלויה בתזמון המקרי בו המחשב הריץ את התהליכים )ולכן התוצאה עלולה להיות שגויה(. • הפתרון :מנגנון שיאפשר רק לתהליך יחיד לפנות למשתנה counter בפרק זמן כלשהו. • הנושא הזה באופן כללי נקרא: תיאום בין תהליכים או process synchronization ©צבי מלמד 8 מנעול lock • • • פתרון אפשרי לבעיה :מנעול ).(lock – רק תהליך יחיד יכול לנעול את המנעול בכל יחידת זמן. – על המנעול מוגדרות פעולות אטומיות של נעילה ושחרור נעילה\רכישה ):(lock/acquire – תהליך המבצע פעולה זו נחסם עד שהמנעול מתפנה ,ואז הוא יכול להתקדם – מובטח שהוא התהליך היחיד שרכש את המנעול )ועל כן היחיד שפונה למשתנה( פתיחה\שחרור ):(unlock/release – שחרור המנעול ,כך שתהליך אחר יוכל לרכוש )לנעול ( אותו. – הטיפול במשתנים המשותפים ,אליהם נרצה לאפשר גישה בלבדית ) (exclusiveיחייב ראשית רכישת המנעול. – בתום הטיפול במשתנים ישוחרר המנעול. ©צבי מלמד 9 מנעול lock • עבודה עם המנעול באופן הזה תבטיח שלא ייווצר מצב מרוץ. • רעיון אפשרי: – נגדיר משתנה בולאני שיהווה את המנעול. – המשתנה עשוי להיות פתוח או סגור )(true or false ©צבי מלמד 10 בעיה ביישום פתרון המנעול • בכדי לרכוש את המנעול מבצע התהליך שתי פעולות: תהליך ב' קרא את מצב המנעול – )א( בדיקת ערכו של המנעול – )ב( עדכון ערכו קרא את מצב המנעול – יש חשש למצב הבא )נניח שהמנעול פתוח(: – ולא השגנו בלבדיות בפניה למשתנים המשותפים. תהליך א' אם ערכו פתוח אזי עדכן את ערכו לסגור אם ערכו פתוח אזי עדכן את ערכו לסגור טפל במשתנים המשותפים טפל במשתנים המשותפים ©צבי מלמד 11 בעיה ביישום פתרון המנעול מסקנה: • מנעול הוא רעיון יפה ,אבל צריך דרך )יותר( מעודנת ,מתוחכמת לממשו מאשר משתנה בוליאני פשוט שערכו נבדק ובמידת האפשר מעודכן ©צבי מלמד 12 פתרונות לבעית מימוש המנעול • שלושה סוגי פתרונות לבעיה כיצד לממש מנעול ולהשיג בלבדיות בטיפול במשתנים: – פתרונות תכנה: • פרוטוקולים )=אוסף כללים( שיקבעו כיצד על התהליכים לנהוג ע"מ שתושג הבלבדיות. – פתרונות חומרה • מסייעים להשיג את התוצאה הרצויה. – פתרונות תכנה מרמה גבוה • מבני נתונים ופעולות מרמה גבוהה,שית ַ מכו ע"י הקומפיילר ,ויאפשרו להשיג את הבלבדיות בנוחות • מימוש הפעולות על ידי הקומפיילר) ,בד"כ תוך שימוש במנגנוני חומרה( ©צבי מלמד 13 בעיית הקטע הקריטי The Critical-Section Problem • • • נניח מערכת בת nתהליכים .לכל אחד מהתהליכים יש קטע קריטי שבו הוא פונה למשתנים או קבצים משותפים ועליו לעשות זאת באופן בלבדי. משמעות המונח קטע קריטי: – לכל אחד מ n-התהליכים יש "קטע קריטי" .זהו קטע שבו הם ניגשים למשאבים משותפים )למשל משתנים או קבצים(. – בגלל בעיות – כגון בעיות מירוץ ,אסור שיותר מתהליך אחד ימצא בקטע הקריטי שלו בו זמנית. – כלומר ,לכל היותר אחד מתוך nהתהליכים מבצע בכל נקודת זמן נתונה את הקטע הקריטי שלו – התהליכים האחרים יבצעו וימצאו באזורים אחרים של התוכנית .כלומר או שהם ימתינו להכנס לקטע הקריטי או שהם יבצעו את "מה שנשאר" – קטע שיורי )(remainder section בעיית הקטע הקריטי: – מה יהיה הפרוטוקול )כללי ההתנהגות( באמצעותו נממש קטע קריטי. ©צבי מלמד 14 בעיית הקטע הקריטי The Critical-Section Problem • הפרוטוקול יכלול: • קטע כניסה )(entry section – סדרת פעולות אותן צריך לבצע תהליך המעוניין להיכנס לקטע הקריטי שלו. • קטע יציאה )(exit section – סדרת פעולות אותן יבצע התהליך בסיום ביצוע הקטע הקריטי שלו • קטע שיורי )(remainder section – קוד שאינו מטפל ב ַ משתנים המשותפים ©צבי מלמד 15 בעיית הקטע הקריטי The Critical-Section Problem 16 ©צבי מלמד שלוש הדרישות לבעיית הקטע הקריטי • בלבדיות ):(mutually exclusiveness – רק תהליך יחיד יוכל לבצע את הקטע הקריטי שלו בכל נקודת זמן. • התקדמות ):(progress – אם mתהליכים כלשהם מעוניינים להיכנס לקטע קריטי )כל תהליך לקטע קריטי של עצמו( ,ואף תהליך אינו מצוי בקטע קריטי .אזי תוך זמן סופי אחד המעוניינים יזכה להיכנס לקטע קריטי = אין קיפאון. • המתנה חסומה ) ,(bounded waitingאי הרעבה – יש חסם על מספר הפעמים שתהליכים אחרים רשאים להיכנס לקטע קריטי. שלהם אחרי שתהליך Pביקש להיכנס לקטע קריטי .שלו ,ועד שבקשתו מסופקת= הוגנות ©צבי מלמד 17 פתרונות תכנה לזוג תהליכים בלבד • Two-Processes Solutions • נניח זוג תהליכים P0, P1 :בלבד. • נניח -כי כל פעולת מכונה ,בפרט השמה ,היא אטומית – )כלומר מתבצעת בשלמותה בלא שניתן יהיה לראות 'תוצאת ביניים' של הפעולה(. – הנחה זאת איננה לגמרי מוצדקת • הערה :במחשבים מודרניים פעולת השמה/פקודת מחשב עשויה להימשך מספר מחזורי זיכרון ,ועל-כן עלול לקרות מצב בו :תהליך א' מתחיל לעדכן משתנה ,תהליך ב' קורא ערך לא תקין של המשתנה ,תהליך א' מסיים את עדכון ערך המשתנה ©צבי מלמד 18 פרוטוקול א' • התהליכים יחלקו משתנה משותףturn : – כאשר ערכו אפס רשאי P0להיכנס לקטע הקריטי – כאשר ערכו אחד ,רשאי P1להיכנס לקטע הקריטי • המשתנה יאותחל לערך כלשהו. { )while (1 while (turn != 0) ; // busy wait הקטע הקריטי ; turn = 1 הקוד של תהליך P0 הקטע השיורי } ©צבי מלמד 19 בדיקת תכונות פרוטוקול א' • נבדוק אילו משלוש הדרישות שהצגנו הפרוטוקול משיג: – בלבדיות מושגת. אינה בהכרח מושגת P0 :לא יוכל להיכנס – התקדמות לקטע הקריטי שלו שוב ,עד ש P1 -ייכנס לקטע הקריטי שלו. – המתנה חסומה מושגת :אם שני התהליכים רוצים להיכנס לקטע הקריטי אזי הם ייכנסו לסירוגין. ©צבי מלמד 20 הבעיה של פרוטוקול א' • פרוטוקול א' לא התעניין בשאלה :האם התהליך האחר בכלל מעוניין להיכנס לקטע הקריטי • ההנחה :הקטע הקריטי מבוצע לסירוגין • התור הועבר לתהליך P0או P1בכל מקרה • על כן עתה נציע שיפור ,נגדיר את המערך: • ; }bool want[2] = {false, false • want[i] == trueמשמע התהליך #iמעוניין להיכנס לק.ק. ©צבי מלמד 21 הבעיה של פרוטוקול א' • פרוטוקול א' לא התעניין בשאלה" :האם התהליך האחר בכלל מעוניין להיכנס לקטע הקריטי" • ההנחה :הקטע הקריטי מבוצע לסירוגין • התור הועבר לתהליך P0או P1בכל מקרה ©צבי מלמד 22 פרוטוקול ב' • נגדיר את המערך: ; }bool want[2] = {false, false • want[i] == trueמשמע התהליך #iמעוניין להיכנס לקטע הקריטי { )while (1 // I want to enter ; want[0] = true // I wait to my pal ;)]while (want[1 הקטע הקריטי ; want[0] = false הקוד של תהליך P0 הקטע השיורי } ©צבי מלמד 23 בדיקת תכונות פרוטוקול ב' • בלבדיות נשמרת :אם חברי רוצה להיכנס אני ממתין. • התקדמות :עלולה שלא להתקיים) .ראה הדוגמא( P0 P1 want[0]=true התוצאה/מסקנה: התהליכים בחסימה הדדית want[1]=true ;]while (want[1 מתקיים ;]while (want[0 מתקיים ©צבי מלמד 24 'פרוטוקול ג :משתנים bool want[2]={false, false}; int turn = 0; while (1) { want[0] = true ; turn = 1 ; // I want to enter as a gentlemen // I allow my pal 2 be the 1st while(want[1] && turn == 1) ; // I wait while it is his turn // AND he also wants to enter הקטע הקריטי want[0] = false ; P0 הקוד של תהליך הקטע השיורי { 25 ©צבי מלמד • פרוטוקול ג' – בדיקת בלבדיות +התקדמות • נניח ששני התהליכים מעוניינים להיכנס – שניהם מבצעיםwant[i] = true: – השני מביניהם שיבצע turn = other-process :יציב אחרון ערך ל turn -לפני לולאת ההמתנה ,וזה יהיה הערך שיוותר במשתנה – ולכן תהליך זה לא יכנס לקטע הקריטי – אבל משנהו כן ייכנס ,וייכנס לבד. – אם רק אחד מעוניין להיכנס )זאת אומרת שהשני נמצא בקטע השיורי( רואים שהוא יוכל להיכנס ,וברור שהוא נכנס לבד ©צבי מלמד 26 פרוטוקול ג' – בדיקת הוגנות • השני שהזין ערך למשתנה הוא האיטי יותר • עמיתו המהיר ייכנס לקטע הקריטי ,יצא ,יסמן שאינו מעוניין להיכנס ,ונניח שאף יספיק לסמן שהוא שוב מעוניין להיכנס. • מיד לאחר מכן ,הזריז יעניק את התור ל ַאיטי ,ובכך ייתקע את עצמו .עד מתי? • עד שהאיטי ייכנס ,יצא ,ויסמן שאינו מעוניין; • לחילופין ,אם האיטי פתאום הפך נורא זריז אזי הוא :יסמן שאינו מעוניין ,שהוא שוב מעוניין ,ושעתה תורו של חברו. • בקיצור :מי שיצא בהכרח מעניק התור למשנהו. ©צבי מלמד 27 • מצאנו פתרון לבעית הקטע הקריטי של שני תהליכים • בדקנו וראינו שהוא מקיים את שלושת הדרישות :בלבדיות, התקדמות ,ואי-חסימה/הוגנות פרוטוקול ג' -סיכום • משתנים: ;}bool want[2]={false, false ;int turn = 0 { )while (1 // I want to enter as a gentlemen // I allow my pal 2 be the 1st ; want[0] = true ; turn = 1 ; )while(want[1] && turn == 1 // I wait while it is his turn // AND he also wants to enter הקטע הקריטי ; want[0] = false הקטע השיורי הקוד של תהליך P0 { ©צבי מלמד 28 פתרונות תכנה לתהליכים רבים Multi Process Solutions • מעודדים מהצלחתינו למצוא פתרון תוכנה לבעית הקטע הקריטי לשני תהליכים – ניגש להתמודד עם האתגר הבא :פתרון תוכנה לאותה בעיה – אבל הפעם ,עבור תהליכים מרובים – nתהליכים • נכיר שני פתרונות: (1אלגוריתם )פרוטוקול( המאפיה (2מימוש מנעולים באמצעות תכנה ©צבי מלמד 29 אלג' המאפיה Bakery Algorithm • מקור השם :מדוכני מזון מהיר בהם מופעל האלגוריתם: – מי שמגיע מקבל מספר – המספר הבא בתור )פחות או יותר( ... – למה פחות או יותר? כי במציאות זה עובד בקלות ופשטות... אבל בתוכנה ,אני בודק מה המספר הכי גבוה עד כה ,ומוסיף אחד – זהו המספר שלי אבל במקביל אלי ,אולי עוד מישהו עשה תהליך כזה ,ואז לשנינו יש אותו מספר ©צבי מלמד 30 אלג' המאפיה Bakery Algorithm • האלגורתים מניח: – לכל תהליך קיים מזהה ייחודי בתחום .0..n-1 • האלג' עשוי להיות מורץ במערכת מקבילית )בת כמה מעבדים(. • סימונים: – ) (a, b) < (c, dעל-פי יחס הסדר הלקסיקוגרפי 'הרגיל'. – ) max(a0, … ,an-1מחזירה ערך הגדול או שווה מכל הai - ).(i=0, …, n-1 ©צבי מלמד 31 אלגוריתם המאפיה Bakery Algorithm • מבני נתונים: ; } bool choosing[n] = { false • -מציין האם התהליך נמצא כרגע בתהליך בחירת מספר לתור )לביצוע הקטע הקריטי( ; }int number[n] = {0 • -מערך של "המספר בתור" של כל תהליך ©צבי מלמד 32 המספר אינו בהכרח ייחודי ,בגלל שתהליך אחר במעבד )הזה או מעבד אחר( עשוי לבקש מספר במקביל 'אלי' אלגוריתם המאפיה { )while (1 אני כרגע בוחר מספר choosing[me] = true ; // = ]number[me ; max(number[0],...,number[n-1]) + 1 סיימתי לבחור choosing[me] = false ; // עבור "כל האחרים" אם מישהו כרגע בוחר מספר ,אני מחכה שיסיים לבחור כל עוד האחר רוצה להיכנס ,והוא בעדיפות על-פני אני ממתין { )for (other = 0; other < n; other++ ; )]while (choosing[other && while (number[other] != 0 < )(number[other], other ; ) )(number[me], me } הקטע הקריטי ; number[me] = 0 קטע שיורי } ©צבי מלמד 33 פתרון שני באמצעות תכנה • פתרון שני לבעיית התיאום )באמצעות תכנה(: – מבוסס על ההנחה שהתוכנית יכולה לחסום פסיקות ,ועל ידי כך להבטיח שהמעבד לא ייגזל ממנה בין בדיקת תנאי להשמה. – הערה :אם הקוד מבוצע ע"י מערכת ההפעלה ,למשל קריאת מערכת שתבצע את זה – ההנחה הזאת איננה בלתי סבירה.... • )בתנאי ש - ...איזה תנאי? – כלומר ,באיזה מקרה ,גם אם ניתן לחסום פסיקות, זה עדיין לא יבטיח לנו את קיום התנאים הדרושים מהקטע הקריטי( • על-סמך ההנחה נוכל לממש מנעולים ,כפי שתוארו קודם לכן ,באופן הבא: ©צבי מלמד 34 חסימת פסיקות )פתרון שני באמצעות תכנה( בדיקה :כאשר המנעול פנוי .1חוסמים את הפסיקות .2בודקים ומגלים שהמנעול פנוי )לא נכנסים ללולאה( { ) lock_acquire( L ; disable_interrupts { )while (L != free ; enable_interrupts ; disable_interrupts } .3נועלים את המנעול .4ומאפשרים פסיקות. • ; L = busy ; enable_interrupts כלומר בין הבדיקה לנעילה הפסיקות חסומות ולכן המעבד לא ייגזל מאתנו. } ©צבי מלמד 35 חסימת פסיקות )פתרון שני באמצעות תכנה( בדיקה :כאשר המנעול תפוס .1נכנסים ללולאה )שוב ושוב( .2חוסמים הפסיקות בסוף כל סיבוב )לפני בדיקת התנאי בכניסה לסיבוב הבא( { ) lock_acquire( L ; disable_interrupts { )while (L != free ; enable_interrupts ; disable_interrupts .3לכן כאשר נבדק התנאי אחרי שהמנעול שוחרר -הפסיקות תהיינה חסומות. • זהו התרחיש שאוזכר בשקף הקודם • בכל מקרה :בין בדיקת ערך המנעול, לנעילתו -הפסיקות חסומות. } ; L = busy ; enable_interrupts } ©צבי מלמד 36 חסימת פסיקות -מגבלות השיטה • אם התכנית עפה כאשר הפסיקות חסומות צריך לדאוג לאפשר אותן • חסימת פסיקות משמעותה עיכוב הטיפול בהן. – לכל הפחות ,החסימה כאן היא לפרק זמן קצר. • הפתרון אינו ישים למערכת בת מספר מעבדים!! – אין הגנה שתמנע ממעבד אחר לגשת למנעול )בזמן הקריטי בין הנקודה שהוא נבדק ועד הנקודה שהוא ננעל( ©צבי מלמד 37 חומרת סינכרון Synchronization Hardware • רוב מערכות החומרה מספקות תמיכה לבעיית הסנכרון • החומרה מספקת פקודת אסמבלר בודדת אשר מתבצעת באופן אטומי! • פקודה זאת לא יכולה להיקטע באמצעה • הפקודה תבצע: – בדיקת ערך של משתנה וגם... – השמת ערך חדש למשתנה או פעולה שקולה אחרת. • הרעיון דומה למה שראינו קודם – בפתרון חסימה של הפסיקות: דואגים לכך ששום דבר לא יכול להתבצע בזמן שבין בדיקת המנעול לבין שינוי ערכו לערך "נעול". ©צבי מלמד 38 חומרת סינכרון Synchronization Hardware • הפקודה המוכרת ביותר בנושא זה נקראת .TestAndSet • להלן אבסטרקציה של מה שפקודת-המכונה הזאת מבצעת: למשתנה מוכנס "בכל מקרה" הערך נעול { )bool TestAndSet( bool &var ; bool old_val = var ; var = true ; return old_val } מוחזר הערך הקודם של המנעול ©צבי מלמד 39 Synchronization Hardware {)bool TestAndSet( bool &var ; bool old_val = var ; var = true ; return old_val } המנעול מאותחל לערך ) falseלא נעול( { )while (1 ; ))while (TestAndSet(lock קטע קריטי ; lock = false כל עוד מוחזר לי שהמנעול כבר היה נעול ‘אני ממתין )(busy wait קטע שיורי { הפתרון מבטיח בלבדיות ,והתקדמות. הוא אינו מבטיח הוגנות או מניעת הרעבה ©צבי מלמד 40 Synchronization Hardware אטומיתswap() שימוש בפקודת : אטומיתswap מציעה פקודת, בעל תכונות דומות,• פתרון דומה void swap(bool &v1, bool &v2) { bool temp = v1 ; v1 = v2 ; v2 = temp ; } 41 ©צבי מלמד Synchronization Hardware using atomic swap { )void swap(bool &v1, bool &v2 ; bool temp = v1 המנעול מאותחל לערך ) falseלא נעול( ; v1 = v2 ; v2 = temp } אני רוצה לנעול – כלומר, להציב ערך trueלמנעול { )while (1 ; key= true )while (key == true ; )swap(key, lock swapמכניס ל key -את ערכו של ,lockלכן עת ערכו של key הוא falseמשמע 'תפסנו' את המנעול פתוח ,והswap - שהחזיר לנו איתות על כך ,גם נעל את המנעול עבורנו. קטע קריטי ; lock = false קטע שיורי { ©צבי מלמד 42 סינכרון בעזרת חומרה – ללא starvation • הפקודות הנ"ל אינן מבטיחות חופש מהרעבה. • נציע פרוטוקול שישתמש ב TestAndSet -ויממש את כל שלוש הדרישות מפרוטוקול סינכרון. • מבני הנתונים המוכרים לכל התהליכים: ; } bool waiting[n] = { false • מציין מי רוצה להיכנס לקטע הקריטי בעזרתו נעביר את הזכות להיכנס בין המעוניינים בזה אחר זה :כל מי שיצא יאתר את הבא אחריו שמעוניין להיכנס ו- 'יזמין' אותו. ; bool lock = false • משתנה זה יציין האם אין אף תהליך שמעוניין להיכנס לקטע קריטי )ואז הראשון שרוצה יכול להיכנס )ורק הקפד לנעול אחריך את הדלת( • לכל תהליך יוגדר משתנה לוקלי keyכמו קודם. ©צבי מלמד 43 סינכרון בעזרת חומרה ללא – starvationקטע הכניסה { )while (1 ; waiting[me] = true ; key = true "גם אני רוצה להכנס" )while (waiting[me] && key ישמש כמו במקרה הקודם עם TestAndSet ] :waiting[meמשתנה זה עשוי לשנות את ערכו כאשר 'חבר' 'יזמין' אותי להיכנס אחריו ,כאשר הוא יצא וישנה את ערך המשתנה עבורי keyישנה את ערכו אם רק אני רוצה להיכנס לקטע קריטי ומתקיים שlock == false - ; )key = TestAndSet(lock ; waiting[me] = false קטע קריטי קטע היציאה קטע שיורי } נראה שקיימת אפשרות להכנס לקטע הקריטי אפילו אם המנעול תפוס )(lock==true האם זה BUGאם שזאת נקודה מרכזית באלגוריתם? ©צבי מלמד 44 סינכרון בעזרת חומרה – ללא starvation קטע היציאה כאשר אני יוצא אני בודק אם יש מישהו שביקש להיכנס לקטע הקריטי ........... קטע קריטי ; other = (me +1) % n )]while (other != me &&!waiting[other אם מצאתי מישהו כזה ; other = (other +1) % n )if (other != me אני מסמן לו שיכנס... ;waiting[other] = false else ; lock = false אחרת – אני משחרר את המנעול הקטע השיורי } הנקודה המרכזית ...אני גואל את otherמלולאת ההמתנה שהוא מצוי בעיצומה. הוא יוצא ממנה ,מבלי שבעצם שוחרר המנעול! שיטת המיטה החמה. ©צבי מלמד 45 compare & swap : קיימת הפקודה הבאהIA32 -• ב compare&swap(mem, R1, R2) { if (mem == R1) { mem = R2 ; return true ; } return false ; } ?TestAndSet כיצד נממש בעזרתה את:• תרגיל 46 ©צבי מלמד ©צבי מלמד 47 סמפורים Semaphores • • • • • סמפור = שיטת תקשורת המבוססת על שימוש בדגלים לאיתות )לכל אות קיימת תנועת דגל מיוחדת(. בהקשר שלנו :התהליכים יאותתו זה לזה האם ניתן\אסור להיכנס לקטע קריטי מטרה :הסמפור משמש בכדי להשיג מנעול כיצד? – סמפור הוא משתנה שלם )(int – הניתן לאיתחול לערך ) 1או מספר גדול יותר( בנוסף לאיתחול ,מוגדרות עליו רק שתי הפעולות האטומיות (aהמתנה\נעילה (bאיתות\שחרור ©צבי מלמד 48 סמפורים Semaphores (a המתנה\נעילה (a איתות\שחרור { )wait(s )while (s <= 0 ; // no-op ; s-- } { )signal(s ; s++ } דרישות אטומיות: s++, s-- .1 .2כאשר הבדיקה ב wait()-נכשלת אז חובה ש s--תהיה אטומית יחד עם בדיקת התנאי שנכשלה • אין מניעה שתהיינה פסיקות ב busy-wait -של הלולאה הwhile- ©צבי מלמד 49 סמפורים • וכיצד ישמש אותנו הסמפור לצורך הגנה על קטע קריטי • נגדיר משתנה שיוכר לכל התהליכיםmutex = 1; : • כל תהליך יבצע: התהליך חסום כל עוד ערכו של mutexאיננו חיובי .ברגע שנכנסנו )ערכו היה חיובי( הקטנו את ערכו ב1- { )while (1 ;)wait(mutex הקטע הקריטי ;)signal(mutex שחרר את הסמפור לאחרים... פקודת signalמגדילה את ערכו ב1- הקטע השיורי } ©צבי מלמד 50 סמפורים • סמפור יכול לסייע לנו גם במשימות סנכרון אחרות ,לא רק בקטע קריטי • לדוגמה :נניח ש P2 -יכול לבצע קטע קוד רק אחרי ש' P1 -הכין' לו נתונים ,כלומר סיים לבצע קטע קוד. איתחול ;synch = 0 P2מבצע P1מבצע קוד ההכנה ;)wait(synch ;)signal(synch קוד השימוש ©צבי מלמד 51 מימוש סמפורים • הפתרונות שראינו עד כה בין בתכנה ובין בחמרה חייבו busy ) :waitingהתהליך מבצע לולאה ריקה בקטע הכניסה שלו( • אם הקטע הקריטי ארוך – ההמתנה מבזבזת הרבה cpu-time • סמפור עם המתנה עסוקה נקרא גם: spinlock : .the process spins while waiting for a lock • יתכן מצב שנעדיף המתנה עסוקה על-פני שתי החלפות הקשר – לדוגמא ,במערכת בת כמה מעבדים ,עם קטע קריטי קצר יחסית • במערכת עם מעבד יחיד ,או כאשר הקטע-הקריטי ארוך – נעדיף שהתהליך ילך לישון עד שהוא יוכל להיכנס לקטע הקריטי ואז יעירו אותו. ©צבי מלמד 52 מימוש סמפורים • נראה כיצד ניתן להשיג את התוצאה בעזרת סמפור "ישנוני": • נגדיר: { struct Sleepy-Semaphore ; int value ערך הסמפור "כרגיל" // רשימת תהליכים struct Process *waiting ; // שממתינים על הסמפור // } ©צבי מלמד 53 5.2.12 עד כאן מימוש סמפורים signal פעולת wait -פעולת ה void signal(Sleepy-Semaphore s) { void wait(Sleepy-Semaphore s) { s.value++ ; s.value-- ; if (s.value <= 0) { if (s.value < 0) { remove a process from add yourself to s.waiting s.waiting and wake it up go to sleep } } } } וגם,• מכיוון שכל אחת משתי הפעולות גם משנה ערך של משתנה בודקת את ערכו אזי יש לדאוג שהן תבוצענה באופן אטומי 54 ©צבי מלמד
© Copyright 2024