Download presentation
Presentation is loading. Please wait.
1
BOOM! count is [1971985225], should be 2000000000
#include <pthread.h> #include <stdio.h> #include <stdlib.h> #define NITER long count = 0; void * ThreadAdd(void * a) { long i, tmp; for(i = 0; i < NITER; i++) { count++; } } int main(int argc, char * argv[]) { pthread_t tid1, tid2; pthread_create(&tid1, NULL, ThreadAdd, NULL); pthread_create(&tid2, NULL, ThreadAdd, NULL); pthread_join(tid1, NULL); /* wait for the thread 1 to finish */ pthread_join(tid2, NULL); /* wait for the thread 2 to finish */ if (count < 2 * NITER) printf("\n BOOM! count is [%ld], should be %ld\n", count, 2*NITER); else printf("\n OK! count is [%ld]\n", count); pthread_exit(NULL); BOOM! count is [ ], should be
2
מבוא לסינכרוניזציה ב-Linux
הצורך בסנכרון הקשרי ביצוע שונים (כגון חוטים ותהליכים) הינו חיוני בכל מערכת הפעלה. Linux מספקת מגוון רחב של מנגנונים לסנכרון בין חוטים ותהליכים, הן כשירות לקוד משתמש והן לצורך שימוש עצמי בספריות ובגרעין. כעת נציג את עיקר מנגנוני הסנכרון עבור חוטים ברמת המשתמש (API).
3
מנעולי mutex מנעול mutex מאפשר לחוט אחד בדיוק להחזיק בו (לנעול אותו) ותהליכון יכול להחזיק יותר מאשר מנעול אחד. כל חוט אחר המבקש להחזיק במנעול ייחסם עד אשר המנעול ישוחרר רק החוט המחזיק במנעול אמור לשחרר אותו (בעלות על המנעול) מנעולי mutex משמשים בדרך-כלל להגנה על גישה לנתונים משותפים, בתוך קטע קוד קריטי, ע"י נעילת המנעול בכניסה לקטע הקריטי ושחרורו בסופו.
4
פעולות על מנעולי mutex (1)
#include <pthread.h> אתחול mutex לפני השימוש: int pthread_mutex_init(pthread_mutex_t *mutex, const pthread_mutex_attr_t *mutexattr); pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; pthread_mutexattr_t mattr; int ret; /* initialize a mutex to its default value */ ret = pthread_mutex_init(&mutex, NULL); פינוי mutex בתום השימוש int pthread_mutex_destroy(pthread_mutex_t *mutex); הפעולה נכשלת אם ה-mutex מאותחל, אבל נעול
5
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
pthread_mutexattr_t mattr; int ret; /* initialize a mutex to its default value */ ret = pthread_mutex_init(&mutex, NULL); default attributes PTHREAD_MUTEX_INITIALIZER or PTHREAD_RMUTEX_INITIALIZER (for recursive mutexes).
6
פעולות על מנעולי mutex (2)
int pthread_mutex_lock(pthread_mutex_t *mutex); הפעולה ממתינה עד שה-mutex מתפנה ואז נועלת אותו נסיון לנעילת mutex: int pthread_mutex_trylock(pthread_mutex_t *mutex); אם ה-mutex כבר נעול הפעולה נכשלת והתכנית ממשיכה, אחרת נועלת אותו. שחרור mutex נעול: int pthread_mutex_unlock(pthread_mutex_t *mutex);
7
פעולות על מנעולי mutex (3)
פרמטרים: mutex – המנעול עליו מבוצעת הפעולה mutexattr – מגדיר את תכונות ה-mutex ב-Linux Threads מוגדרת רק תכונת "סוג" ה-mutex, המתבטאת בהתנהגות ה-mutex בנעילה ובשחרור, כמוצג בשקף הבא ברירת המחדל – NULL – mutex מסוג "מהיר" מומלץ לעבוד עם mutex מסוג "בודק שגיאות", כדי למנוע מצבים בעייתיים כגון אלו המסומנים באדום בשקף הבא ערך מוחזר: 0 בהצלחה, ערך אחר בכישלון
8
סוגים של מנעולי mutex סוג ה-mutex נעילה חוזרת ע"י החוט המחזיק במנעול
שחרור מנעול ע"י חוט שאינו מחזיק במנעול שחרור מנעול ע"י החוט המחזיק במנעול mutex מהיר DEADLOCK מותר mutex רקורסיבי מגדיל מונה נעילה עצמית ב-1 מקטין מונה נעילה עצמית ב-1. ה-mutex נשאר נעול עד שהמונה מגיע ל-0 mutex בודק שגיאות כשלון
9
BOOM! count1 is [16372624], should be 2000000000
#include <pthread.h> #include <stdio.h> #include <stdlib.h> #define NITER pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; long count = 0, count1 = 0; void * ThreadAdd(void * a) { for(long i = 0; i < NITER; i++) { pthread_mutex_lock( &mutex ); count++; pthread_mutex_unlock( &mutex ); } for(i = 0; i < NITER; i++) count++; } int main(int argc, char * argv[]) { pthread_t tid1, tid2; pthread_mutex_init(&mutex, NULL); pthread_create(&tid1, NULL, ThreadAdd, NULL); pthread_create(&tid2, NULL, ThreadAdd, NULL); pthread_join(tid1, NULL); /* wait for the thread 1 to finish */ pthread_join(tid2, NULL); /* wait for the thread 2 to finish */ if (count < 2 * NITER) printf("\n BOOM! count is [%ld], should be %ld\n", count, 2*NITER); else printf("\n OK! count is [%ld]\n", count); printf("\n BOOM! count1 is [%ld], should be %ld\n", count1, 2*NITER); printf("\n OK! count1 is [%ld]\n", count1); pthread_exit(NULL); OK! count is [ ] BOOM! count1 is [ ], should be
10
דוגמה: מנעולי mutex להלן דוגמה המשתמשת ב-mutex:
pthread_mutex_t m; int count; void update_count() { pthread_mutex_lock(&m); count = count * 5 + 2; pthread_mutex_unlock(&m); } int get_count() { int c; pthread_mutex_lock(&m); c = count; pthread_mutex_unlock(&m); return c; } מדוע צריך להגן על הגישה ל-count בתוך update_count()? כדי למנוע שיבוש ערך count בעדכונים מחוטים שונים. מדוע צריך להגן על הגישה ל-count בתוך get_count()? כדי למנוע קבלת תוצאות חלקיות הנוצרות במהלך העדכון שימו לב! גם אם ביטוי ההגדלה היה count++, לא מובטח שהקוד הנפרש באסמבלר הינו אטומי, ולכן יש להפעיל מנגנון סנכרון לפי הצורך.
11
כעת נעבור לדוגמאות נוספות
Similar presentations
© 2025 SlidePlayer.com. Inc.
All rights reserved.