
WaitOne ממתין עד שמבצעים Set.WaitOne ולא מוסיפים דבר עד לחיצה על הכפתור.WaitHandle.WaitAll ממתין לכל האירועים במערך, ו-WaitHandle.WaitAny חוזר עם הראשון שמסתיים.הטקסט המלא של הדקות הראשונות בהרצאה «Threads - חלק 6» בקורס הווידאו של PracticU – כתוביות בעברית עם זמן התחלה לכל פסקה. כך תוכלו לקרוא ולחפש את הנושאים לפני שמתחילים ללמוד.
הרכיב הראשון שאנחנו הולכים לראות נקרא מיוטקס. בואו נפתח פה דוגמה נפרדת עבור מיוטקס. הרכיבים הבאים שאנחנו הולכים לראות בנוגע לכל הסינכרוניזציה בין טרדים, זה רכיבים מאוד מעניינים שמסוגלים לשלוח פולסים או סיגנלים אחד לשני, וכך לציין מתי אפשר להיכנס לקטע קריטי ומתי לעצור,
בעזרת מצב של סיגנל, כלומר שליחת אות מסוימת ולפי האות הזאת אפשר לדעת מתי להיכנס ומתי לעצור. בואו נסתכל על הרכיבים. אז בעצם אנחנו הולכים לראות שני רכיבים שיורשים מאותו הבייס והרכיבים שאנחנו הולכים לראות נקראים Manual Reset Event ו-Auto Reset Event.
אנחנו צריכים להבין מה זה אומר ה-Reset, מה זה אומר ה-Manual ומה זה אומר ה-Auto בכדי לדעת איך לעבוד איתם. לצורך הדוגמה בואו קודם כל נבהיר מה ההבדל בין Manual reset event לבין Auto reset event ואז נדע איך לעבוד איתם.
אז בואו ניקח כאן קודם כל דוגמה הפעם win form לגבי Manual reset event. בואו נפתח פה רקט חדש ומה שאני רוצה לעשות, אני רוצה לעצב את הטופס כך שיש לי איזשהו לחצן ושתי תיבות ליסטבוקס.
ואני רוצה שהלחצן יאפשר לפתוח שני טרדים שיעבדו על הליסטבוקס. בואו ניקח פה common controls, ניקח פה איזשהו בטון, והלחצן הזה אמור לבצע פליטה על המידע שאנחנו הולכים להכניס לתוך הליסטבוקסים.
הנה יש לנו פה ליסטבוקס ראשונה, אני מבצע קופי פייסט, עוד ליסטבוקס, הנה הלחצן נמצא פה, נצמצם טיפה את הטופס, אוקיי, כותבים את זה טיפה למעלה ובואו ניתן להם תכונות.
ראשית יש לנו פה את הטופס, נוריד ממנו את הכותרת, נגדיר שהוא יהיה במרכז המסך, יש לנו פה את הלחצן, בלחצן הזה נקרא btn-set-reset, תכף אנחנו נבין מה ההבדל בין סט לבין ריסט ונרשום עליו את המילה סט.
הליסטבוקס הראשונה נקרא לה list even numbers ולליסטבוקס השנייה נקרא lst odd numbers. מה שאנחנו רוצים לעשות, אנחנו רוצים לפתוח שני טרדים.
טרד ראשון ימלא את הליסט הראשונה רק במספרים זוגיים, הטרד השני ימלא את הליסט השנייה במספרים אי-זוגיים רנדומליים.
אנחנו רוצים שאיך שהתוכנית עולה, אוטומטית המערכת תיצור לנו את הטרדים האלה. בואו נגיד אפילו כאן, Thread, T-Even, נגדיר איזושהי פונקציה, נקרא לה Feel-Even Numbers, נגדיר שה-T-Even Background Thread ונתחיל אותו.
מבצע את אותו הדבר בדיוק עבור טרד אחר נקרא לו t-odd עבור מספרים אי-זוגיים. בואו נגדיר אותם בצורה כזאת, יש לנו קודם כל הגדרה של האובייקטי הטרד, לאחר מכן אנחנו מגדירים שהם backgrounds ולבסוף מתחילים אותם.
נשאר לנו לבנות את הפונקציות. הפונקציה הראשונה נגדיר אותה פה, תבצע ריצה בוא נניח 100 פעם ואנחנו רוצים לייצר איזשהו מספר רנדומלי אז בואו לצורך הדוגמה ניקח פה פעם אחת אובייקט רנדום, האובייקט הזה יאפשר לנו לייצר איזשהו מספר רנדומלי int num שווה rmd next בין 0 ל-100 כולל 0 לא כולל 100 אפילו בואו נעשה את זה עד 1000 פרע ואנחנו רוצים לוודא שהמספר הזה
הוא אכן מספר זוגי כי אנחנו רוצים למלא רק מספרים זוגיים לכן בואו נפתח פה איזשהו while כל עוד המספר שנוצר מודולו 2 לא שווה לאפס זה כמובן אומר שהוא אי-זוגי אז אנחנו רוצים להמשיך ולייצר עוד אחד שהוא יהיה מספר זוגי.
זאת אומרת אנחנו הולכים לצאת מהעלולה הזאת רק כאשר יש לנו ביד מספר רנדומלי זוגי. אחרי שיש לנו מספר רנדומלי זוגי אנחנו יכולים לגשת ל-List Even Numbers Items Add ולהוסיף את המספר הזה לליסט, מעולה.
בכדי שהדבר הזה לא ייקח על פי את השנייה, בואו ניקח פה פרד סליפ 100 מילי שניות, וכך כל התהליך הזה לוקח 10 שניות. אנחנו לא רוצים שהוא יתקע את הטופס, אז כמובן יש לנו את זה בטרד נפרד, ואנחנו רוצים לשכפל כל הפונקציה הזאת לפונקציה שתאפשר לבצע הוספה של עוד נמברס.
פה אנחנו צריכים לבדוק כל עוד המספר הוא זוגי אנחנו רוצים לייצר עוד אחד ובצורה כזאת אנחנו יכולים להריץ את הכל ואם אנחנו נריץ את התוכנית אנחנו נראה שהכל מתמלא קודם כל הפונקציה הראשונה בעצם אמור היה להתמלא שניהם כנראה שיש לי פה שגיאת copy paste בואו נמצא אותה זה אמור להיות, אם אנחנו
נריץ אנחנו נראה ששניהם אמורים לעבוד בו זמנית או פה זה עובד בסדר שניהם אמורים לעבוד בו זמנית 10 שניות וזה נגמר אבל אנחנו רוצים שהלחצן הזה ישלוט על הפעילות כלומר הטרדים פועלים ברקע אין בעיה אבל אנחנו רוצים שלחיצה על הלחצן תשהה אותם ולחיצה נוספת תגרום להם להמשיך לעבוד.
קודם כל בואו ניכנס ללחצן ונכתוב את הקוד שלו. אז מה שאנחנו רוצים לעשות זה לבצע בדיקה מה בעצם כתוב בטקסט של הלחצן. אם כתוב עליו סט אנחנו רוצים לבצע פעולה א', אחרת אנחנו רוצים לבצע פעולה ב'.
מה אנחנו רוצים לעשות? אנחנו רוצים לגרום לטרדים להפסיק ולהמשיך כתלות בלחיצות של הלחצן. יש לנו אפשרות להשתמש ב-manual reset event.
בואו ניקח משתנה כזה, manual reset event, ונגדיר אובייקט ממנו. ואנחנו צריכים לתת לו איזשהו משתנה בוליאני שנקרא initial state, ואנחנו הולכים לתת לו false.
ועכשיו בואו קודם כל נבין מה ההבדל בין set לבין reset, ומה זה ה-false הזה שנתנו לו. ויש שני מונחים בעולם ה-Manual Reset Event וה-Auto Reset Event שאנחנו צריכים להכיר.
אחד נקרא Set והשני נקרא Reset. Set זה אומר שהמשאב פנוי. Reset אומר שהמשאב תפוס, בבקשה להמתין. אם אנחנו מבינים את שני הדברים האלה יהיה לנו מאוד קל להבין איך אנחנו עובדים עם המנואל ריסט איבנט והאוטו ריסט איבנט ותכף נראה מה ההבדל בין מנואל לבין אוטו.
אז קודם כל הסט אומר המשאב פנוי וניתן לעבוד עליו. איזה משאב שאתם רוצים? ריסט אומר לא לא לא, המשאב תפוס, אתם לא יכולים לעבוד עליו עד שלא יבצעו סט וישחררו אותו.
הפולס שכתבנו פה אומר שזה ריסט זה אומר שהמשאב תפוס. כל מה שאנחנו צריכים לעשות בלחצן זה אם מישהו מבצע סט, מה שאנחנו צריכים לעשות זה manual reset event.set וזה משחרר אותו.
כאן אנחנו רוצים לעשות manual reset event reset וזה תופס אותו, תופס את המשאב. בנוסף אנחנו רוצים כמובן לבצע שינוי של הטקסט שכתוב על הלחצן.
בואו נחליף לו את הטקסט הזה ל-reset ובואו נחליף לו את הטקסט הזה ל-set בחזרה. ועכשיו בשביל שהפונקציות עצמן גם יוכלו להתבצע או לא להתבצע אנחנו צריכים בתוך הפונקציה לבצע manual reset event נקודה wait one זה בעצם מבצע את ההמתנה ופה סיימנו את כל התשתית אז אנחנו מריצים את התוכנית איך שהרצנו אני מזכיר לכם
הטרדים אוטומטית מותחלים. למה? מפני שהתחלנו אותם בקונסטרקטור. זאת אומרת שבדוגמה הזאת קיימים טרדים שהתחילו לרוץ.
אבל למה אנחנו לא רואים שום דבר שמתרחש בליסטבוקס שיש כאן, כמו שמקודם ראינו? מפני שאיך שהלולאות התחילו, אוטומטית יש פה המתנה ואנחנו רואים שכרגע הגדרנו שהמנואל ריסט איבנט תפוס, כלומר המשאב תפוס ואנחנו צריכים להמתין עד שיבצעו סט וישחררו אותו.
כאשר אנחנו מבצעים סט, זה אומר שאנחנו צריכים ללחוץ על הלחצן הזה, אז אוטומטית שחררנו את הטרד ושניהם יכולים לעבוד. אם אנחנו עושים ריסט, אז אנחנו בעצם תופסים את המשאב וה-wait-one גורם למערכת בעצם להיתקע.
טרדים נתקעים עד שאנחנו לא מבצעים עוד פעם set ומשחררים את המערכת. כך במשך 10 שניות המערכת ממשיכה לרוץ. בואו נמתין את ה-10 שניות האלה, נראה שזה הסתיים ונסגור את הטופס.
לצורך ההבנה או בעצם לצורך ה-UI שנראה קצת יותר טוב, במקום add, בואו נקרא ל-insert ונכניס את המספר במיקום הראשון ואז נוכל גם לראות את זה יותר טוב.
אם אנחנו נריץ כרגע, אנחנו נוכל לראות שאני לוחץ על set, אני משחרר את העבודה, לחיצה נוספת, מבצעת reset וזה תופס לי את המשאב או ליתר דיוק אנחנו מגדירים שהמשאב כרגע תפוס ולכן ה-wait 1 גורמת לכל טרדג' שהגיע אליו להיכנס לבלוק סינכרוניזד ולהמתין.
אנחנו מבצעים סט, משחררים אותו וממשיך ריסט, תופסים אותו. סט, משחררים, ריסט, תופסים. ואז המשאב נחשב כתפוס.
בואו נבין למה זה נקרא Manual reset. אז קודם כל, ברגע שביצענו סט, שחררנו את המשאב אבל רק אם אנחנו לוחצים על ריסט אז ריסט מתבצע. אם לחצנו על סט או קראנו לפונקציית סט, ריסט לא מתבצע אוטומטית וזאת הסיבה שזה נקרא Manual reset event כי אנחנו בצורה מנואלית כלומר בצורה ידנית צריכים לקרוא לריסט בכדי לנעול את הרכיב הזה.
זאת הסיבה שלחיצה אחת על סט משחררת אותו, ורק אם אנחנו נלחץ עוד פעם אנחנו ננעל אותו. זה הקטע של ה-manual, זה לא היה מתבצע בצורה אוטומטית. עכשיו, אם אני אקח את כל התוכנית הזאת ואני אשכפל אותה, בואו נפתח את התיקייה בכלל, נראה איפה שמרנו את התוכנית, אני אחזור ל-visual studio,
אני אסגור בכלל את כל Visual Studio. אני אחזור לתיקייה ומה שאני רוצה לעשות זה לשכפל את כל התוכנית הזאת שהייתה Manual Reset Event בכדי שעותק של ה-Manual יישאר ואני רוצה תוכנית אחרת שנקראת Auto Reset Event.
בואו נפתח את Visual Studio הפעם עם ה-Auto Reset Event ונראה מה יקרה אם כל מה שאנחנו עושים זה משנים את הרכיב Manual Reset Event ל-Auto Reset Event.
לצורך הדוגמה הזאת אנחנו צריכים לשנות גם את השם של ה-Solution, גם את השם של ה-Project. בואו ניגש ל-Properties, נשנה את השם של ה-Cובץ Execution שנוצר מ-Manual Reset Event ל-Auto Reset Event.
אנחנו יכולים לשנות עוד פרמטרים של קובץ ה-Execution עצמו, אבל אין הרבה צורך לעשות את זה, לדוגמה את ה-Title ולדוגמה את ה-Product ל-Auto-Reset Event.
בואו נסגור הכל, נשנה אפילו את ה-Namespace של התוכנית. בואו ניגש ל-Namespace ונשנה אותו ל-Auto-Reset Event, כולל Refactoring כמו שצריך.
ומה שעשינו זה שכפלנו את כל העותק של התוכנית הזאת לעותק נפרד, אנחנו רוצים להשתמש ברכיב שנקרא auto reset event ולראות מה ההבדל.
בואו נשנה את זה מ-manual ל-auto וכאן מ-manual ל-auto reset event גם כאן וגם כאן ואחרי ששינינו רק את הקונספט הזה שהאובייקט עצמו הפך להיות auto reset event בואו נבין מה זה אומר.
אז כאשר דיברנו על manual reset אמרנו שאם אנחנו עושים סט הוא אוטומטית לא חוזר לריסט ארטו ריסט אומר שאם אנחנו עושים סט הוא אוטומטית חוזר לריסט שימו לב מה יקרה אם אנחנו מריצים עכשיו את התוכנית קודם כל בגלל שיש לנו פולס בהתחלה ונעול ורק כאשר אנחנו לוחצים על סט אנחנו משחררים אבל שימו לב מה קרה רק אחד הצליח
להיכנס ואוטומטית הוא נעל אחריו את הדלת אם אנחנו לוחצים עכשיו על ריסט לא קורה כלום, היא אוטומטית בריסט. סט משחרר את השני, ריסט לא עושה כלום. סט משחרר אחד.
שימו לב שהם לא חייבים להיות לפי הסדר, ויכול להיות שטרד אחד לוקח את השליטה שוב ושוב ושוב פעמים, ואחר כך הטרד השני, אין פה איזשהו סדר קבוע.
זה מצב שנקרא רייס, מרוץ. איזה טרד שמשיג, מצליח להיכנס. לא כל כך הגיוני שריסט לא יעשה כלום, ולכן בואו טיפה נשנה את ה-UI ואת ההתנהגות של ה-UI כך שהלחצן הזה לא ייקרא סט וריסט, אלא הלחצן הזה יהיה אך ורק סט.
כי ריסט מתבצע אוטומטית. אז בואו נחזור לפה, נכתוב עליו סט, נחזור לקוד, נגדיר שהשם של האיבנט זה רק btn-set ולא reset, נבצע ריפקטורינג עבור השם של האיבנט וניפטר מכל מה שיש בתוכו פרט לסט.
זאת פעולה קצת יותר הגיונית והלחצן כל מה שהוא יעשה זה רק סט בלי ריסט. אז אם אנחנו לוחצים על הסט אנחנו משחררים רק אחד ויכול להיות אותו טרד כל הזמן ויכול להיות שהוא יתחלף לטרד השני אבל הנקודה היא שהריסט מתבצע אוטומטית כאשר הסט יתבצע.
זאת אומרת, סט שחרר את המשאב, ווייט וואן נתן לטרד מסוים להיכנס, לא משנה איזה, הראשון שנכנס אוטומטית נועל אחריו את הדלת, ולכן זה נחשב שהריסט, כלומר הנעילה, התבצעה אוטומטית, וזאת הסיבה שהוא נקרא Auto-Reset Event, כי בצורה אוטומטית הוא נעל אחריו את הדלת.
אפשר לבצע אנלוגיה בין ה-Manual reset event ו-Auto reset event למצב של דלתות אוטומטיות. תחשבו שאתם עכשיו רוצים להיכנס לאיזשהו קניון ויש לכם את הדלת מסתובבת או את המחסום הזה שאתם עוברים ואוטומטית נסגר אחריכם, כמו לדוגמה שיש בתחנות רכבת.
אתם עוברים ואוטומטית נסגר. מישהו עובר ואוטומטית נסגר. זה יהיה ה-Auto reset event. ה-Manual reset event זה מחסום כזה, כמו זרוע שעולה מלא מלא מלא מלא מלא אנשים יכולים להיכנס ומתי שמישהו רוצה הוא בצורה יזומה סוגר את המחסום.
זה יהיה המנואל ריסט איבנט שמאפשר להמון המון להיכנס ורק בצורה מנואלית ידנית הוא נסגר. אז יש לנו פה את הארטו ריסט איבנט ואת המנואל ריסט איבנט שמאפשרים לנו לבצע סינכרוניזציה בין טרדים.
כמובן אנחנו בוחרים את זה שיותר מתאים ללוגיקה שלנו.