סנכרון תהליכים וחוטים Process and Thread Synchronization חלק ראשון 1 אלן אזאגורי © מרץ 2002 נושאים  מוטיבציה  הגדרות  פיתרון כללי  מנעולים ותמיכתם בחומרה עמוד 2 אלן אזאגורי © מרץ.

Download Report

Transcript סנכרון תהליכים וחוטים Process and Thread Synchronization חלק ראשון 1 אלן אזאגורי © מרץ 2002 נושאים  מוטיבציה  הגדרות  פיתרון כללי  מנעולים ותמיכתם בחומרה עמוד 2 אלן אזאגורי © מרץ.

‫סנכרון תהליכים וחוטים‬
‫‪Process and Thread‬‬
‫‪Synchronization‬‬
‫חלק ראשון‬
‫‪1‬‬
‫אלן אזאגורי ©‬
‫מרץ ‪2002‬‬
‫נושאים‬
‫‪ ‬מוטיבציה‬
‫‪ ‬הגדרות‬
‫‪ ‬פיתרון כללי‬
‫‪ ‬מנעולים ותמיכתם בחומרה‬
‫עמוד ‪2‬‬
‫אלן אזאגורי ©‬
‫מרץ ‪2002‬‬
‫מוטיבציה‬
‫‪int c = 0; // Global variable‬‬
‫‪Thread B:‬‬
‫)‪while (c > -10‬‬
‫;‪c = c - 1‬‬
‫;‪kill A‬‬
‫;”‪print “B wins‬‬
‫‪‬‬
‫‪Thread A:‬‬
‫)‪while (c < 10‬‬
‫;‪c = c + 1‬‬
‫;‪kill B‬‬
‫;”‪print “A wins‬‬
‫הנחות‬
‫– קריאה‪/‬כתיבה של משתנה היא אטומית‬
‫– פעולה אריתמטית על המשתנה אינה אטומית‬
‫‪‬‬
‫‪‬‬
‫‪‬‬
‫מי זוכה?‬
‫האם תמיד יש זוכה?‬
‫האם שניהם עשויים‬
‫לזכות?‬
‫עמוד ‪3‬‬
‫לפעמים ‪ A‬ולפעמים ‪B‬‬
‫לא‬
‫כן‪ ,‬כאשר הפקודה ‪ kill‬אסינכרונית‬
‫אלן אזאגורי ©‬
‫מרץ ‪2002‬‬
‫בעית יצרן‪/‬צרכן‬
‫‪ ‬הגדרות‬
‫– שני חוטים (יצרן וצרכן) רצים באותו מרחב זיכרון‬
‫– מערך חסום (מעגלי) מכיל את העצמים המיוצרים‬
‫– ליצרן מצביע )‪ (pp‬למקום הפנוי הבא במערך‬
‫– לצרכן מצביע )‪ (cp‬למקום הבא המכיל את העצם המוכן‬
‫הבא‬
‫– מספר העצמים המוכנים הוא ‪c‬‬
‫‪n-1‬‬
‫‪c‬‬
‫‪0‬‬
‫‪cp‬‬
‫עמוד ‪4‬‬
‫‪pp‬‬
‫אלן אזאגורי ©‬
‫מרץ ‪2002‬‬
)‫צרכן (המשך‬/‫בעית יצרן‬
int c = 0; // Global variable
Producer:
repeat
while (c>=n) nop;
buf[pp] = new item;
pp = (pp+1) mod n;
c = c + 1;
until false;
Consumer:
repeat
while (c<1) nop;
consume buf[cp];
cp = (cp+1) mod n;
c = c - 1;
until false;
‫ בעיות‬
c ‫– עדכון בו זמנית (לא מוגן) של‬
‫ יכול להיות גבוה (נמוך) מן הערך הנכון‬c ‫– לכן ערכו של‬
2002 ‫מרץ‬
© ‫אלן אזאגורי‬
5 ‫עמוד‬
‫בעית החלב‬
‫את‪/‬ה‪:‬‬
‫מסתכל במקרר‬
‫הולך לסופר‬
‫קונה חלב‬
‫חוזר הביתה‬
‫מכניס חלב למקרר‬
‫שותף‪:‬‬
‫מסתכל במקרר‬
‫הולך לסופר‬
‫קונה חלב‬
‫חוזר הביתה‬
‫מכניס חלב למקרר‬
‫‪ ‬בעיה‪ :‬יותר מדי חלב!‬
‫עמוד ‪6‬‬
‫אלן אזאגורי ©‬
‫מרץ ‪2002‬‬
‫בעית החלב‬
‫פיתרון ‪ 1‬‬
‫‪ ‬פיתרון‪ :‬להשאיר פיתקה‬
‫מסתכל במקרר‬
‫אם אין חלב‬
‫אם אין פתקה‬
‫השאר פתקה‬
‫קנה חלב‬
‫הורד פתקה‬
‫‪ ‬בעיה‪ :‬כל אחד קפץ לחדר לכתוב פתק ולא שם לב‬
‫לכך שהשני השאיר פתק‬
‫עמוד ‪7‬‬
‫אלן אזאגורי ©‬
‫מרץ ‪2002‬‬
‫בעית החלב‬
 2 ‫פיתרון‬
‫ בודקים האם גם‬,‫ לאחר השארת הפיתקה‬:‫ פיתרון‬
‫השותף השאיר פיתקה‬
Thread A:
leave note A
if (no note B) then
if (no milk) then
buy milk
remove note A
Thread B:
leave note B
if (no note A) then
if (no milk) then
buy milk
remove note B
!‫ קיים תסריט בו אף אחד לא יקנה חלב‬:‫ בעיה‬
2002 ‫מרץ‬
© ‫אלן אזאגורי‬
8 ‫עמוד‬
‫בעית החלב‬
 3 ‫פיתרון‬
‫ שבירת הסימטריה‬:‫פיתרון‬
Thread A:
Thread B:
leave note A
leave note B
X:while (note B) do nop
Y:if (no note A) then
if (no milk) then
if (no milk) then
buy milk
buy milk
remove note A
remove note B
!‫ יקנה חלב‬A ,)‫במקרה של "תחרות" (שניהם משאירים פתק בו זמנית‬
‫חסרונות‬



‫– רק לשני תהליכים‬
‫– לא הוגן‬
2002 ‫מרץ‬
© ‫אלן אזאגורי‬
9 ‫עמוד‬
‫הגדרות‬
‫‪ ‬מרוץ )‪(Race Condition‬‬
‫– בד"כ התכנית (המקבילית) עובדת נכון‬
‫– קיים תסריט בו התכנית לא עובדת נכון‬
‫• לרוב בגלל שבירה איזושהי הנחת אטומיות שאינה‬
‫מתקיימת‬
‫‪ ‬בדוגמת בעית החלב‬
‫– השארת פיתקה‬
‫– בדיקה האם השותף השאיר פיתקה‬
‫עמוד ‪10‬‬
‫אלן אזאגורי ©‬
‫מרץ ‪2002‬‬
‫הגדרות (המשך)‬
‫‪ ‬מניעה הדדית – ‪mutual exclusion‬‬
‫– מנגנונים המבטיחים שרק חוט אחד מבצע סדרת‬
‫פעולות מסוימות בזמן נתון‬
‫• אטומיות ביחס לחוטים אחרים‬
‫‪ ‬קטע קריטי – ‪critical section‬‬
‫– קטע קוד שרק חוט אחד מבצע בזמן נתון‬
‫קריטי‬
‫לא קריטי‬
‫עמוד ‪11‬‬
‫אלן אזאגורי ©‬
‫יציאה‬
‫מרץ ‪2002‬‬
‫הגדרות (המשך)‬
‫‪ ‬אטומיות – ‪Atomicity‬‬
‫– בביצוע סדרת פקודות ע"י חוט אחד‪,‬חוטים אחרים אינם‬
‫יכולים לראות תוצאות חלקיות ‪ -‬סדרת הפקודות נראית כמו‬
‫פעולה אחת שאיננה ניתנת לחלוקה ("פעולה אטומית")‬
‫– ניתן להשיג בעזרת מנגנון של מניעה הדדית‬
‫‪ ‬דוגמא‬
‫– העברת כספים מחשבון לחשבון‬
‫‪Thread B:‬‬
‫)‪if (account1+account2<min‬‬
‫… ‪then‬‬
‫‪Thread A:‬‬
‫;‪account1:= account1 – sum‬‬
‫;‪account2:= account2 + sum‬‬
‫– לא נאפשר לחוטים אחרים לראות מצב בו הכסף נמשך‬
‫מחשבון א' אך לא הגיע לחשבון ב'‬
‫עמוד ‪12‬‬
‫אלן אזאגורי ©‬
‫מרץ ‪2002‬‬
‫תכונות של פתרון לבעיית הקטע‬
‫הקריטי‬
‫‪ ‬חובה‬
‫– רק חוט אחד בקטע קריטי (מניעה הדדית)‬
‫– אם יש בקשות להיכנס לקטע קריטי‪ ,‬אזי חוט אחד ייכנס (אין‬
‫קיפאון – ‪)deadlock‬‬
‫‪ ‬רצוי‬
‫– חוט המבקש להיכנס לקטע קריטי בסופו של דבר יצליח (אין‬
‫הרעבה – ‪)starvation‬‬
‫– עבור כל זוג חוטים‪ ,‬אם הם יתחרו ‪ n‬פעמים להיכנס לקטע‬
‫קריטי‪ ,‬הם יזכו מספר דומה של פעמים )‪(fairness‬‬
‫עמוד ‪13‬‬
‫אלן אזאגורי ©‬
‫מרץ ‪2002‬‬
(bakery) ‫אלגוריתם קופת חולים‬
(1) ‫לפיתרון בעית הקטע הקריטי‬
‫ שימוש במספרים‬
‫– חוט נכנס לוקח מספר‬
‫– חוט שמספרו הקטן ביותר נכנס לקטע הקריטי‬
‫ ניסיון ראשון‬
Thread i:
initially number[i]=0
number[i]=max{number[1],…,number[n]}+1;
for all ji do
wait until number[j]=0 or (number[j]>number[i])
critical section
number[i]=0 // Exit critical section
2002 ‫מרץ‬
© ‫אלן אזאגורי‬
14 ‫עמוד‬
‫אלגוריתם קופת חולים )‪(bakery‬‬
‫לפיתרון בעית מניעה הדדית )‪(1‬‬
‫‪ ‬בעיה‬
‫– חוט ‪ i‬ו‪ j-‬קוראים את המערך בו זמנית‬
‫– שניהם "בוחרים" את אותו מספר‬
‫‪ ‬קיפאון!‬
‫עמוד ‪15‬‬
‫אלן אזאגורי ©‬
‫מרץ ‪2002‬‬
(bakery) ‫אלגוריתם קופת חולים‬
(2) ‫לפיתרון בעית מניעה הדדית‬
‫ נשתמש במס' הזהות של התהליך כדי לשבור‬
‫סימטריה‬
Thread i:
initially number[i]=0
number[i]=max{number[1],…,number[n]}+1;
for all ji do
wait until number[j]=0 or
()number[j],j)>(number[i],i)) // lexicographical
// comparison
critical section
number[i]=0 // Exit critical section
2002 ‫מרץ‬
© ‫אלן אזאגורי‬
16 ‫עמוד‬
‫אלגוריתם קופת חולים )‪(bakery‬‬
‫לפיתרון בעית מניעה הדדית )‪(2‬‬
‫‪ ‬בעיה‬
‫– חוט ‪ i‬ו‪ j-‬קוראים את המערך בו זמנית )‪(i>j‬‬
‫– חוט ‪ i‬כותב את המספר‪ ,‬בודק את ערכו כנגד‬
‫‪ number‬ונכנס לקטע הקריטי (]‪ number[j‬עדיין ‪)!0‬‬
‫– חוט ‪ j‬ממשיך וגם הוא נכנס לקטע הקריטי!‬
‫‪ ‬אין מניעה הדדית!‬
‫– התהליך עם מספר זהות גבוה )‪ (i‬מזדרז להיכנס‬
‫לקטע הקריטי לפני ש‪ j-‬הספיק לכתוב את ]‪number[j‬‬
‫עמוד ‪17‬‬
‫אלן אזאגורי ©‬
‫מרץ ‪2002‬‬
(bakery) ‫אלגוריתם קופת חולים‬
(3) ‫לפיתרון בעית מניעה הדדית‬
‫ נוודא שאין חוטים באמצע בחירת מספר לפני‬
‫ההשוואות‬
‫ביצוע‬
Thread i:
initially number[i]=0
choosing[i]=true
number[i]=max{number[1],…,number[n]}+1;
choosing[i]=false
for all ji do
wait until choosing[j]=false
for all ji do
wait until number[j]=0 or
()number[j],j)>(number[i],i))
critical section
number[i]=0 // Exit critical section
2002 ‫מרץ‬
© ‫אלן אזאגורי‬
18 ‫עמוד‬
‫אלגוריתם קופת חולים )‪(bakery‬‬
‫לפיתרון בעית מניעה הדדית )‪(3‬‬
‫‪ ‬אין הרעבה (ולכן אין קיפאון) והפתרון הוגן‬
‫– הוכחה בתרגול‬
‫‪ ‬פיתרון מסורבל‬
‫– הרבה פעולות‪ ,‬הרבה משתנים‬
‫‪ ‬הפיתרון לא יעבוד בסביבות מרובות מעבדים‬
‫– ‪Out of order execution‬‬
‫‪ ‬קיימים אלגוריתמים אחרים‬
‫‪ ‬בהמשך נלמד על פתרונות אחרים‬
‫עמוד ‪19‬‬
‫אלן אזאגורי ©‬
‫מרץ ‪2002‬‬
‫מנעולים )‪(locks‬‬
‫‪ ‬מבטיחים גישה בלעדית למידע באמצעות‬
‫שתי פונקציות‬
‫– )‪ – lock_acquire(lock‬פעולה חוסמת (אם‬
‫המנעול תפוס)‬
‫– )‪ – lock_release (lock‬משחרר את המנעול‬
‫עמוד ‪20‬‬
‫אלן אזאגורי ©‬
‫מרץ ‪2002‬‬
‫( – דוגמא‬locks) ‫מנעולים‬
‫צרכן‬/‫ דוגמא – בעית יצרן‬
Producer:
repeat
while (c>n) nop;
buf[pp] = new item;
pp = (pp+1) mod n;
lock_acquire(c_lock)
c = c + 1;
lock_release(c_lock)
until false;
Consumer:
repeat
while (c<1) nop;
consume buf[cp];
cp = (cp+1) mod n;
lock_acquire(c_lock)
c = c - 1;
lock_release(c_lock)
until false;
?while-‫ ב‬c ‫ האם מספיק להגן רק על שינוי‬
?‫– מה קורה במקרה של יותר מצרכן אחד‬
2002 ‫מרץ‬
© ‫אלן אזאגורי‬
21 ‫עמוד‬
‫מימוש מנעולים‬
‫‪lock_release(L):‬‬
‫)(‪disableInterrupts‬‬
‫‪L := FREE‬‬
‫)(‪enableInterrupts‬‬
‫‪‬‬
‫אטומיות‬
‫– מובטחת ע"י חסימת פסיקות‬
‫‪‬‬
‫‪lock_acquire(L):‬‬
‫)(‪disableInterrupts‬‬
‫‪while LFREE do‬‬
‫)(‪enableInterrupts‬‬
‫)(‪disableInterrupts‬‬
‫‪L := BUSY‬‬
‫)(‪enableInterrupts‬‬
‫‪Busy wait‬‬
‫– ניתן למנוע ע"י ניהול תור החוטים המחכים‬
‫‪‬‬
‫‪‬‬
‫למה חשוב לאפשר פסיקות בתוך הלולאה?‬
‫ומה קורה במערכות מרובות מעבדים?‬
‫– חסימת פסיקות אינה מבטיחה אטומיות‪...‬‬
‫– דורש תמיכה מהחומרה לפקודות "חזקות" יותר‬
‫עמוד ‪22‬‬
‫אלן אזאגורי ©‬
‫מרץ ‪2002‬‬
‫מימוש מנעולים‬
test&set ‫תמיכת חומרה‬
test&set(boolvar) 
‫ והחזר ערך קודם‬true ‫– כתוב ערך‬
lock_acquire(L):
while test&set(L)
do nop
lock_release(L):
L := false
‫ – מנעול פנוי‬L = false –
‫ – מנעול תפוס‬L = true –
2002 ‫מרץ‬
© ‫אלן אזאגורי‬
23 ‫עמוד‬
‫מימוש מנעולים‬
‫תמיכת חומרה ‪compare&swap‬‬
‫‪compare&swap(mem, r1, r2) ‬‬
‫– אם בזיכרון )‪ (mem‬ערך זהה לרגיסטר ‪ ,r1‬כתוב ערך ‪r2‬‬
‫והחזר הצלחה‬
‫– אחרת החזר ערך כישלון‬
‫‪lock_acquire(L):‬‬
‫‪lock_release(L):‬‬
‫‪r1 = false‬‬
‫‪L := false‬‬
‫‪r2 = true‬‬
‫))‪while not compare&swap(L, r1, r2‬‬
‫‪do nop‬‬
‫‪ ‬ניתן לממש מונה אטומי‬
‫עמוד ‪24‬‬
‫אלן אזאגורי ©‬
‫מרץ ‪2002‬‬
‫מימוש מנעולים מודרני‬
‫‪load-linked & store conditional‬‬
‫‪ ‬ממומש ברוב הארכיטקטורות החדישות‬
‫– ‪Compaq’s Alpha, IBM’s PowerPC, MIPS4000‬‬
‫‪ ‬צמד פקודות‬
‫– )‪ – LL(mem‬קרא את ערך הזיכרון‬
‫– )‪ – SC(mem, val‬אם לא היתה כתיבה ל‪ mem-‬מאז ה‪-‬‬
‫)‪ LL(mem‬האחרון‪ ,‬כתוב ערך ‪ val‬והחזר הצלחה (אחרת‬
‫כשלון)‬
‫‪ ‬יותר כח מאשר ל‪compare&swap-‬‬
‫– ניתן לזהות כתיבות עוקבות של אותו ערך‬
‫עמוד ‪25‬‬
‫אלן אזאגורי ©‬
‫מרץ ‪2002‬‬
‫מימוש מנעולים‬
load-linked & store conditional
lock_acquire(L):
success = false
repeat
LL(L)
if not L then
success = SC(L, true)
until success
2002 ‫מרץ‬
© ‫אלן אזאגורי‬
lock_release(L):
L := false
26 ‫עמוד‬
load-linked & store conditional
‫ מתי חשוב לזהות כתיבות עוקבות של אותו‬
?‫ערך‬
‫ הוצאת האיבר הראשון‬,‫– ברשימה מקושרת‬
remove_first(head):
element = NULL
A:if headNULL then
LL(head)
next_head = head->next
element = head
if not SC(head, next_head)
goto A;
return element
2002 ‫מרץ‬
© ‫אלן אזאגורי‬
27 ‫עמוד‬