שיעור 22: תנאי מרוץ בזיכרון גלובלי — למה צריך atomics
עד עכשיו כמעט כל kernel שכתבתם נתן לכל thread תא פלט משלו: c[i] = a[i] + b[i], כאשר thread מספר i הוא היחיד שנוגע אי-פעם ב-c[i]. מכיוון ששני threads לעולם לא חולקים יעד, הסדר שבו הם רצים לא משנה — התוצאה תמיד נכונה. אבל יש בעיות שמכריחות הרבה threads לעדכן את אותו תא בדיוק: לספור כמה ערכים נופלים לכ
דמיינו 30 ילדים שחולקים דף ספירה אחד שכתוב עליו 5. שניים מציצים בו יחד, שניהם רואים 5, שניהם כותבים 6 — וספירה אחת נעלמה. פעולה אטומית היא חוק שרק ילד אחד מחזיק את העיפרון בכל רגע (קורא, מוסיף, כותב), וכך שום ספירה לא הולכת לאיבוד.
- תנאי מרוץ (race condition)
- באג שבו התוצאה תלויה בתזמון ובסדר הבלתי-צפויים שבהם threads ניגשים לאותו נתון. לפעמים עובד, לפעמים לא.
- קריאה-שינוי-כתיבה (read-modify-write)
- הפעולה x++ היא בעצם שלושה צעדים: לקרוא את x, להוסיף 1, ולכתוב את x. thread אחר יכול להידחק בין הצעדים.
- עדכון אבוד (lost update)
- שני threads קוראים את אותו ערך ישן ושניהם כותבים בחזרה, כך שאחד ההגדלות פשוט נעלם והספירה יוצאת נמוכה מדי.
- פעולה אטומית (atomic operation)
- פעולת read-modify-write בלתי-ניתנת-לחלוקה שאף thread אחר אינו יכול לקטוע — הפתרון למרוץ, למשל atomicAdd.