PracticU

Threads - חלק 5

בלי כתוביותעם כתוביות
PracticU › קורס תכנות מתקדם - #Advanced .NET C › Threads - חלק 5
מילון מושגים:
בנאי - מתודה מיוחדת שמופעלת אוטומטית בעת יצירת אובייקט ממחלקה, ומאתחלת את ערכיו ההתחלתיים.
פונקציה - קטע קוד בעל שם שמבצע משימה מוגדרת, מקבל ערכי קלט (פרמטרים) ויכול להחזיר תוצאה. מאפשרת לארגן קוד ולהשתמש בו שוב.
רכיב - יחידת בניין עצמאית וניתנת לשימוש חוזר בתוך מערכת או ממשק משתמש, שאחראית על חלק מוגדר מהתפקוד.

Threads - חלק 5
השיעור מציג שלושה רכיבי סינכרוניזציה נוספים: מיוטקס, סמאפור ו-ReaderWriterLock. בכולם המטרה זהה, לאפשר לטרדים לגשת למשאב משותף בצורה מסודרת.
מיוטקס
1. נעילה ברמת מערכת ההפעלה: מוניטור ולוק פועלים בתוך התוכנית. המיוטקס פועל ברמת מערכת ההפעלה ומזוהה לפי השם שנותנים לו. כל תוכנית שנותנת את אותו שם מקבלת את אותו מיוטקס, וכך אפשר להגן על קובץ שניגשים אליו כמה תוכניות.
2. WaitOne ו-ReleaseMutex: קוראים ל-WaitOne כדי לנעול. אם מישהו אחר נעל, הקריאה נתקעת עד שהוא משחרר. אחרי הקטע הקריטי קוראים ל-ReleaseMutex.
3. הדגמה: שתי תוכניות נפרדות עם אותו שם מיוטקס. הראשונה נועלת, והשנייה נתקעת ב-WaitOne עד ששחררו אותה, ורק אז נכנסת לקטע הקריטי.
סמאפור
4. כמה טרדים במקביל: סמאפור מאפשר לקבוצה מוגבלת של טרדים לעבוד יחד על משאב. לדוגמה, מתוך מאה טרדים רק עשרה יכולים לעבוד על הדאטאבייס בו זמנית.
5. Semaphore(initial, max): הבנאי מקבל כמה טרדים מותר להכניס בהתחלה וכמה מקסימום במקביל. Release משחרר כניסה נוספת, ו-WaitOne נכנס או מחכה.
6. הדגמה: עם מקסימום שלושה, ההדפסות הראשונות הן 1, 3 ו-5, ואחרי שהם מסתיימים נכנסים 2, 4 ו-6. עם מקסימום שניים נכנסים בכל רגע רק שניים.
ReaderWriterLock
7. קריאה במקביל, כתיבה לבד: כמה טרדים יכולים לקרוא בו זמנית, אבל כשטרד כותב אף אחד אחר לא קורא ולא כותב.
8. שלוש פונקציות עיקריות: AcquireReaderLock לקריאה, AcquireWriterLock לכתיבה, ו-ReleaseReaderLock או ReleaseWriterLock לשחרור. לכל רכישה מעבירים זמן המתנה מקסימלי, בדוגמה 1000 מילישניות.
9. סדר הכניסה: כשכותב מבקש את המנעול, המערכת מחכה שכל הקוראים יסיימו ולא נותנת כניסה לקוראים חדשים. אחרי הכתיבה המנעול חוזר לקורא או לכותב הבא.
שלושת הרכיבים נותנים בחירה לפי אופי הגישה למשאב: נעילה ברמת מערכת ההפעלה, מספר מוגבל של טרדים, או הפרדה בין קריאה לכתיבה.
השיעור הבא בקורס: Threads - חלק 6

פרקי ההרצאה: Threads - חלק 5

  1. 00:00

    מהו MUTEX

  2. 01:30

    נעילה ברמת מערכת ההפעלה

  3. 02:52

    נעילה עם WaitOne ו-ReleaseMutex

  4. 05:23

    הדגמת נעילה בין שתי תוכניות

  5. 08:38

    רכיב ה-SEMAPHORE

  6. 13:22

    הגבלת מספר Threads עם Semaphore

  7. 18:42

    רכיב Reader Writer Lock

תמלול ההרצאה: Threads - חלק 5

הטקסט המלא של הדקות הראשונות בהרצאה «Threads - חלק 5» בקורס הווידאו של PracticU – כתוביות בעברית עם זמן התחלה לכל פסקה. כך תוכלו לקרוא ולחפש את הנושאים לפני שמתחילים ללמוד.

  1. 00:05

    הרכיב הראשון שאנחנו הולכים לראות נקרא mutex בואו נפתח פה דוגמה נפרדת עבור mutex אוקיי אז יש לנו פה תוכנית console application פשוטה ואנחנו הולכים לבדוק את הרכיב הזה שנקרא mutex אז ראשית יש לנו כאן את המשתנה הזה בואו ניתן לו לא Initially owned false, אנחנו לא רוצים to ownership,

  2. 01:03

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

  3. 01:28

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

  4. 01:44

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

  5. 01:59

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

  6. 02:25

    נתתם להם את אותו השם ומבחינת מערכת ההפעלה זה אותו המיוטקס ולכן הוא מתייחס לאותו ריסורס. בואו נראה דוגמא. נניח שאנחנו רושמים כאן press enter for locking יש לנו פה consort read line ולצורך נעילה כל מה שאנחנו צריכים לעשות זה מיוטקס נקודה wait one.

  7. 03:00

    אם אף אחד לא נעל לפני זה את המיוטקס אז יש לנו זכות לבצע את הנעילה ואנחנו ממשיכים להתקדם ל-Critical Section. אוקיי, בואו נרשום פה. Console. foreground, I'm in the Critical Section.

  8. 03:45

    פה החזרנו את הצבע למצב ההתחלתי שלו. ומה שאנחנו רוצים לעשות זה לרשום למשתמש. Press Enter for Releasing. שוב פעם, Console. ReadLine בשביל להמתין. ויש לנו פה את הפונקציה שנקראת release mutex שמאפשרת לשחרר אותו, זאת אומרת כאן אנחנו מבצעים נעילה על ידי wait1 תוך כדי זה שיש לנו אפשרות להיכנס בעצמנו.

  9. 04:29

    אם מישהו אחר נעל ואנחנו מנסים לבצע wait1 אנחנו כמובן נעוף לסינכרוניז ואנחנו לא נוכל להיכנס אלא אם כן הוא ישחרר. אז מי שנעל מצליח להיכנס ובסופו של דבר חייב לבצע שחרור, ברגע שהוא ביצע שחרור אנחנו יכולים להיכנס ובואו נדפיס איזושהי הודעה mute text release ונמתין.

  10. 05:11

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

  11. 05:36

    אז אנחנו מריצים ואנחנו רואים שיש לנו פה Press Enter for Locking ואנחנו יכולים ללחוץ על Enter ואנחנו רואים שהמערכת נכנסה לקריטיקל סקשן, ביצעה אותו וממתינה שנשחרר אותה.

  12. 05:53

    אבל בשלב הזה אני לא הולך לשחרר את המערכת, אני הולך לחזור לוויז'ואל סטודיו ולהריץ עוד פעם את וויז'ואל סטודיו על ידי קונטרול F5 כאילו שתוכנית אחרת רצה ומנסה להגיע לאותו המשאב.

  13. 06:14

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

  14. 06:30

    בתוכנית האחרת, השנייה, אני לוחץ על Enter ושימו לב שלמרות שלחצתי על Enter היא תקועה. למה היא תקועה? מפני שעוד לא שחררנו את המיוטקסט בתוכנית הראשונה ולכן התוכנית השנייה נתקעה פה ב-Wait 1 ולא הגיעה ל-Critical Faction.

  15. 06:56

    כעת בואו נחזור בחזרה לתוכנית הראשונה ונלחץ בתוכנית הראשונה על Enter בכדי לשחרר את המיוטקס ותוך כדי זה שאני עושה את זה תסתכלו מה קורה בתוכנית השנייה זאת שלמעלה.

  16. 07:16

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

  17. 07:43

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

  18. 08:12

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

  19. 08:38

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

  20. 09:08

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

  21. 09:52

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

  22. 10:23

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

  23. 10:57

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

  24. 11:15

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

  25. 11:36

    זאת אומרת שהטרד הראשון יגרום להצגה של 10 פעמים 1, הטרד השני 10 פעמים 2, הטרד השלישי 10 פעמים 3 וכן הלאה. בואו נריץ את זה ונראה שכל פעם מוצגים לנו כל המספרים מ-1 עד 6, כך עשר פעמים.

  26. 12:03

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

  27. 12:32

    זאת הסיבה שכל הזמן אנחנו רואים כל המספרים מ-1 עד 6 מוצגים ושימו לב שאנחנו לא חייבים לראות אותם באותו הסדר. לדוגמה, כאן אנחנו רואים 1, 2, ואז 4, ואז 3, ואז 5, ואז 6.

  28. 12:48

    פה אנחנו רואים 2, 1, 3, 5, 6. פה אנחנו רואים 4, 1, 2, 3, 5 וכולי. זאת אומרת, הסדר אכן הוא לא קבוע, אבל עדיין ששת הטרדים עובדים על הפונקציה הזאת.

  29. 13:10

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

  30. 13:28

    בואו נבדוק איך אפשר לעשות את זה. בואו ניקח משתנה static, סמאפור, נקרא לו mySemaphore ובתוך המיין נבנה אובייקט ממנו. עכשיו הקונסטרקטור שלו מקבל שני ערכים אינטג'ריים אינישיאל קאונט ומקסימום קאונט. בואו נבין מה הם על ידי זה שנפתח משתנים שיסבירו את ערכם.

  31. 14:07

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

  32. 14:32

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

  33. 14:59

    mySemaphore.release מקסימום טרד הלארד. זאת אומרת בנינו את האובייקט ואמרנו על ההתחלה אף טרד אסור לו להתחיל ולעבוד עד שאנחנו לא נגיד כמה טרדים אנחנו מעוניינים להתחיל ובמקסימום אנחנו רוצים שרק שלושה טרדים יוכלו לעבוד בו זמנית על המשאב שלנו בהקשר שלנו זאת הפונקציה print

  34. 15:30

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

  35. 15:50

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

  36. 16:29

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

  37. 16:49

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

  38. 17:10

    בואו נריץ ונסתכל מה קורה. ואנחנו רואים קודם כל שיש לנו פה המתנה עד שאנחנו לא לוחצים enter, בואו נלחץ enter, ונראה שרק שלושה טרדים הגיעו ויש להם את היכולת לעבוד על הפונקציה, זה יהיה 1, 3, 5.

  39. 17:28

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

  40. 17:44

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

  41. 17:55

    נריץ, שמיכה center, אחד ושתיים כרגע עובדים על הפונקציה. כל הטרדים האחרים, ארבעת הטרדים האחרים ממתינים בכלל, הם תקועים ב-wait one.

  42. 18:08

    עכשיו שניים אחרים יכולו להיכנס, זה יהיה ארבע ושלוש, ורק כשהם יסתיימו, השניים האחרונים יוכלו להיכנס, שזה יהיה שש וחמש.

  43. 18:22

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

  44. 18:50

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

  45. 19:35

    בואו ניקח כאן איזשהו משתנה, נניח ליסט של אינט,

לקורס המלא: קורס תכנות מתקדם ב‑#C ודוט-נט

ההרצאה הקודמת: Threads - חלק 4

ההרצאה הבאה: Threads - חלק 6

הרצאות קשורות מקורסים אחרים

  • Threads

קורסים נוספים במסלול

  • קורס WinForms - תוכנות רגילות בווינדוס
  • פרויקט מעשי ב-#C - בונים מחשבון פשוט
  • פרויקט מעשי ב-#C - ספר טלפונים
  • פרויקט מעשי ב-#C - תוכנת צייר
  • קורס ADO.NET - חיבור אתר למסד נתונים
  • קורס WCF - תקשורת למתקדמים בדוט-נט