PracticU

Threads - חלק 6

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

Threads - חלק 6
השיעור עוסק באירועים שמעבירים אות בין טרדים: ManualResetEvent ו-AutoResetEvent. שניהם יורשים מ-WaitHandle ולכן משתמשים בהם באותה צורה. נתחיל מההבנה של המשמעות של Set ו-Reset.
Set ו-Reset
1. Set ו-Reset: Set אומר שהמשאב פנוי. Reset אומר שהמשאב תפוס, וכל מי שקורא ל-WaitOne ממתין עד שמבצעים Set.
2. ManualResetEvent: אחרי Set הוא נשאר פתוח, ורבים יכולים לעבור דרכו. הוא נסגר רק כשקוראים ל-Reset במפורש, וזו הסיבה לשם ידני.
3. AutoResetEvent: אחרי Set הטרד הראשון שעובר מחזיר את האירוע אוטומטית ל-Reset. לכן רק טרד אחד עובר בכל Set.
דוגמה: כפתור שמשהה שני טרדים
4. התוכנית: טופס עם כפתור ושתי ListBox. כל טרד ממלא ListBox אחת: הראשון מספרים זוגיים והשני מספרים אי-זוגיים, אחת ל-100 מילישניות במשך כעשר שניות.
5. ההתחלה: ה-ManualResetEvent מאותחל ל-false, כלומר תפוס. לכן הטרדים נתקעים ב-WaitOne ולא מוסיפים דבר עד לחיצה על הכפתור.
6. הכפתור: לחיצה מבצעת Set והטרדים ממשיכים. לחיצה נוספת מבצעת Reset והם נתקעים שוב. הטקסט של הכפתור מתחלף בין Set ל-Reset לפי המצב.
השוואה ל-AutoResetEvent
7. הפיכה לאוטומטי: מעתיקים את הפרויקט, מחליפים את האירוע ל-AutoResetEvent ואת הכפתור משאירים רק עם Set. כל לחיצה משחררת טרד אחד, ואחריו האירוע נסגר אוטומטית.
8. סדר לא קבוע: הטרד שנכנס יכול להיות כל אחד משניהם, ואפשר שטרד אחד יקבל את השליטה שוב ושוב. זה מצב של מרוץ (Race), ולכן צריך לבחור את הסוג שמתאים ללוגיקה.
9. אנלוגיה: ManualResetEvent הוא מחסום שנשאר פתוח לכל מי שעובר, ו-AutoResetEvent הוא דלת שנסגרת מאחורי מי שנכנס.
דוגמאות שימוש
10. הורדת דף: מחלקה מורידה HTML בטרד נפרד, שומרת לקובץ, סופרת תגיות ומציגה את התוצאה. בלי סינכרוניזציה הקובץ התקבל ריק. עם ManualResetEvent שמאותחל ל-false, כל הפונקציות נעצרות עד שההורדה מסתיימת וקוראת ל-Set.
11. ציור צורות: מלבן, משולש וקו מצוירים בטרדים נפרדים. AutoResetEvent מבטיח שכל ציור מתחיל רק אחרי שהקודם סיים, כך שהצבע לא מתאפס באמצע ציור.
12. WaitAll ו-WaitAny: WaitHandle.WaitAll ממתין לכל האירועים במערך, ו-WaitHandle.WaitAny חוזר עם הראשון שמסתיים.
הבחירה בין שני האירועים תלויה בשאלה אם רוצים שהמשאב יישאר פתוח לכולם או שיעבור לטרד אחד בכל פעם.
השיעור הבא בקורס: Threads - חלק 7

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

  1. 00:00

    סנכרון Threads עם Mutex ו-Events

  2. 01:07

    ההבדל בין ManualResetEvent ל-AutoResetEvent

  3. 01:48

    בניית טופס WinForm עם שני Threads

  4. 04:04

    מילוי ListBox במספרים זוגיים ואי-זוגיים

  5. 09:40

    שליטה ב-Threads עם ManualResetEvent

  6. 10:21

    משמעות SET ו-RESET

  7. 17:53

    מעבר ל-AutoResetEvent

  8. 22:50

    אנלוגיה לדלתות אוטומטיות

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

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

  1. 00:05

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

  2. 00:42

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

  3. 01:12

    אנחנו צריכים להבין מה זה אומר ה-Reset, מה זה אומר ה-Manual ומה זה אומר ה-Auto בכדי לדעת איך לעבוד איתם. לצורך הדוגמה בואו קודם כל נבהיר מה ההבדל בין Manual reset event לבין Auto reset event ואז נדע איך לעבוד איתם.

  4. 01:35

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

  5. 02:04

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

  6. 02:28

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

  7. 03:13

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

  8. 03:43

    הליסטבוקס הראשונה נקרא לה list even numbers ולליסטבוקס השנייה נקרא lst odd numbers. מה שאנחנו רוצים לעשות, אנחנו רוצים לפתוח שני טרדים.

  9. 04:09

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

  10. 04:23

    אנחנו רוצים שאיך שהתוכנית עולה, אוטומטית המערכת תיצור לנו את הטרדים האלה. בואו נגיד אפילו כאן, Thread, T-Even, נגדיר איזושהי פונקציה, נקרא לה Feel-Even Numbers, נגדיר שה-T-Even Background Thread ונתחיל אותו.

  11. 05:08

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

  12. 05:35

    נשאר לנו לבנות את הפונקציות. הפונקציה הראשונה נגדיר אותה פה, תבצע ריצה בוא נניח 100 פעם ואנחנו רוצים לייצר איזשהו מספר רנדומלי אז בואו לצורך הדוגמה ניקח פה פעם אחת אובייקט רנדום, האובייקט הזה יאפשר לנו לייצר איזשהו מספר רנדומלי int num שווה rmd next בין 0 ל-100 כולל 0 לא כולל 100 אפילו בואו נעשה את זה עד 1000 פרע ואנחנו רוצים לוודא שהמספר הזה

  13. 06:31

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

  14. 07:02

    זאת אומרת אנחנו הולכים לצאת מהעלולה הזאת רק כאשר יש לנו ביד מספר רנדומלי זוגי. אחרי שיש לנו מספר רנדומלי זוגי אנחנו יכולים לגשת ל-List Even Numbers Items Add ולהוסיף את המספר הזה לליסט, מעולה.

  15. 07:25

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

  16. 07:53

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

  17. 08:33

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

  18. 09:04

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

  19. 09:35

    מה אנחנו רוצים לעשות? אנחנו רוצים לגרום לטרדים להפסיק ולהמשיך כתלות בלחיצות של הלחצן. יש לנו אפשרות להשתמש ב-manual reset event.

  20. 09:55

    בואו ניקח משתנה כזה, manual reset event, ונגדיר אובייקט ממנו. ואנחנו צריכים לתת לו איזשהו משתנה בוליאני שנקרא initial state, ואנחנו הולכים לתת לו false.

  21. 10:11

    ועכשיו בואו קודם כל נבין מה ההבדל בין set לבין reset, ומה זה ה-false הזה שנתנו לו. ויש שני מונחים בעולם ה-Manual Reset Event וה-Auto Reset Event שאנחנו צריכים להכיר.

  22. 10:30

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

  23. 11:21

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

  24. 11:39

    הפולס שכתבנו פה אומר שזה ריסט זה אומר שהמשאב תפוס. כל מה שאנחנו צריכים לעשות בלחצן זה אם מישהו מבצע סט, מה שאנחנו צריכים לעשות זה manual reset event.set וזה משחרר אותו.

  25. 12:23

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

  26. 12:41

    בואו נחליף לו את הטקסט הזה ל-reset ובואו נחליף לו את הטקסט הזה ל-set בחזרה. ועכשיו בשביל שהפונקציות עצמן גם יוכלו להתבצע או לא להתבצע אנחנו צריכים בתוך הפונקציה לבצע manual reset event נקודה wait one זה בעצם מבצע את ההמתנה ופה סיימנו את כל התשתית אז אנחנו מריצים את התוכנית איך שהרצנו אני מזכיר לכם

  27. 13:15

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

  28. 13:29

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

  29. 13:59

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

  30. 14:27

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

  31. 14:43

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

  32. 15:06

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

  33. 15:33

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

  34. 15:46

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

  35. 16:36

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

  36. 17:09

    אני אסגור בכלל את כל Visual Studio. אני אחזור לתיקייה ומה שאני רוצה לעשות זה לשכפל את כל התוכנית הזאת שהייתה Manual Reset Event בכדי שעותק של ה-Manual יישאר ואני רוצה תוכנית אחרת שנקראת Auto Reset Event.

  37. 17:44

    בואו נפתח את Visual Studio הפעם עם ה-Auto Reset Event ונראה מה יקרה אם כל מה שאנחנו עושים זה משנים את הרכיב Manual Reset Event ל-Auto Reset Event.

  38. 17:59

    לצורך הדוגמה הזאת אנחנו צריכים לשנות גם את השם של ה-Solution, גם את השם של ה-Project. בואו ניגש ל-Properties, נשנה את השם של ה-Cובץ Execution שנוצר מ-Manual Reset Event ל-Auto Reset Event.

  39. 18:24

    אנחנו יכולים לשנות עוד פרמטרים של קובץ ה-Execution עצמו, אבל אין הרבה צורך לעשות את זה, לדוגמה את ה-Title ולדוגמה את ה-Product ל-Auto-Reset Event.

  40. 18:41

    בואו נסגור הכל, נשנה אפילו את ה-Namespace של התוכנית. בואו ניגש ל-Namespace ונשנה אותו ל-Auto-Reset Event, כולל Refactoring כמו שצריך.

  41. 19:03

    ומה שעשינו זה שכפלנו את כל העותק של התוכנית הזאת לעותק נפרד, אנחנו רוצים להשתמש ברכיב שנקרא auto reset event ולראות מה ההבדל.

  42. 19:19

    בואו נשנה את זה מ-manual ל-auto וכאן מ-manual ל-auto reset event גם כאן וגם כאן ואחרי ששינינו רק את הקונספט הזה שהאובייקט עצמו הפך להיות auto reset event בואו נבין מה זה אומר.

  43. 19:44

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

  44. 20:19

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

  45. 20:33

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

  46. 20:45

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

  47. 21:15

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

  48. 21:46

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

  49. 22:10

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

  50. 22:41

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

  51. 23:01

    אתם עוברים ואוטומטית נסגר. מישהו עובר ואוטומטית נסגר. זה יהיה ה-Auto reset event. ה-Manual reset event זה מחסום כזה, כמו זרוע שעולה מלא מלא מלא מלא מלא אנשים יכולים להיכנס ומתי שמישהו רוצה הוא בצורה יזומה סוגר את המחסום.

  52. 23:21

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

  53. 23:38

    כמובן אנחנו בוחרים את זה שיותר מתאים ללוגיקה שלנו.

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

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

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

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

  • Threads

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

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