PracticU

יצירת תהליכון - Thread

בלי כתוביותעם כתוביות
PracticU › קורס C למתקדמים - עבודה מול חומרה Win32 › יצירת תהליכון - Thread
מילון מושגים:
תהליכון - יחידת ביצוע בתוך תהליך, המאפשרת להריץ כמה מהלכים במקביל ולחלוק את אותו זיכרון.
Visual Studio - סביבת פיתוח משולבת (IDE) של מיקרוסופט לכתיבה, ניפוי והרצה של קוד, בעיקר בשפות .NET.
לולאה - מבנה בקרה שחוזר על קטע קוד שוב ושוב כל עוד תנאי מתקיים או עבור כל פריט באוסף.
מעבד - יחידת העיבוד המרכזית של המחשב, שמבצעת את הפקודות של התוכניות ומנהלת את החישובים.
פרמטר - ערך שמועבר לפונקציה או לפקודה כקלט, ומשפיע על אופן פעולתן ועל התוצאה שהן מחזירות.
בנאי - מתודה מיוחדת שמופעלת אוטומטית בעת יצירת אובייקט ממחלקה, ומאתחלת את ערכיו ההתחלתיים.
אסינכרוני - אופן פעולה שבו פעולה ארוכה רצה ברקע והתוכנית ממשיכה בלי להמתין לה, ומטופלת כשתסתיים.
זיכרון - רכיב מהיר ונדיף שבו המחשב שומר נתונים ותוכניות בזמן ריצתם. תוכנו נמחק עם כיבוי המחשב.

יצירת תהליכון - Thread
יצירת תהליכון (Thread) ב-C++ מוצגת בהרצאה הזו כדרך להריץ כמה קטעי קוד במקביל בתוך תוכנית Win32 קונסולה ב-Visual Studio. המרצה מראה גם מה קורה כשנתונים מועברים בין תהליכונים בצורה שגויה.
השלבים העיקריים
1. פרויקט קונסולה נקי: נפתח פרויקט Win32 קונסולה ריק עם קובץ main ב-C++, וההדפסות נעשות למסך.
2. השהיה בלולאה: לולאה של מיליוני איטרציות מעלה את ה-CPU מאוד ופוגעת בהקלטה, לכן מוסיפים Sleep(100), כלומר עשירית השנייה, ובכך מודפסים כעשרה מספרים בשנייה.
3. הפונקציה CreateThread: היא מחזירה handle לתהליכון. הפרמטרים הם מאפייני אבטחה, גודל מחסנית (0 לברירת המחדל), כתובת הפונקציה שתרוץ בתהליכון, פרמטר שיועבר לה, דגלי יצירה ומזהה התהליכון, שאפשר להעביר בו 0 אם הוא לא נחוץ.
4. חתימת פונקציית התהליכון: הפונקציה מוגדרת כ-DWORD WINAPI ומקבלת מצביע מסוג void. המרצה מסביר שהפרמטר הזה הוא מצביע כללי שאפשר להמיר לכל טיפוס.
5. שני תהליכונים במקביל: שני תהליכונים מדפיסים את האותיות a ו-b, והם מתחלפים כי כל אחד מהם עושה Sleep ונותן לשני לרוץ. אין הבטחה לסדר ההרצה, ולכן לפעמים מודפס b לפני a.
6. העברת נתונים באמצעות מבנה: מעבירים מבנה עם כמה שדות. אם מעבירים כתובת של משתנה שנמצא על המחסנית של הפונקציה הראשית, המשתנה נהרס כשהפונקציה מסתיימת, והתהליכון קורא ערכים שגויים.
7. הקצאה בהיפ: הפתרון שהמרצה מציג הוא להקצות את המבנה ב-new, להעביר את המצביע אליו, ולהוסיף בנאי שמאתחל את השדות.
8. מאה תהליכונים: בלולאה נוצרים מאה תהליכונים, והמספרים מודפסים בסדר לא צפוי, כי המערכת מחליטה בכל רגע איזה תהליכון ירוץ.
טעויות נפוצות
- העברת כתובת של משתנה מקומי לתהליכון אחר היא שגיאה לוגית שקשה לאתר, כי התוכנית ממשיכה לרוץ ולעיתים לא מתרסקת.
- ברגע שעובדים עם תהליכונים נכנסים לעולם אסינכרוני, ואי אפשר לדעת מראש מתי כל קטע קוד ירוץ.
בסיום ההרצאה ברור איך יוצרים תהליכון ומעבירים לו נתונים בבטחה, וכמה חשוב לנהל את הזיכרון שהם משתמשים בו. המרצה מציין שאפשר להגדיר פונקציות שונות לתהליכונים שונים, ושיחזור לנושא בהמשך הקורס.
השיעור הבא בקורס: UltraVnc - Source Code compile

פרקי ההרצאה: יצירת תהליכון - Thread

  1. 00:00

    פתיחת פרויקט Console וקובץ main

  2. 01:59

    הכללת stdio.h והמתנה ל-Enter

  3. 02:43

    הרעיון: thread שמדפיס למסך

  4. 03:27

    Sleep למניעת עומס על המעבד

  5. 06:28

    שתי לולאות שרצות במקביל

  6. 07:06

    CreateThread וההנדל שלו

  7. 08:01

    LPTHREAD_START_ROUTINE ופרמטרים

  8. 10:57

    בעיית הטיפוס: std call ו-Win API

תמלול ההרצאה: יצירת תהליכון - Thread

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

  1. 00:03

    טוב, בואו היום אנחנו נלמד על שרדים, על תהליכוניים, נפתח את הוויז'ואל סטודיו, קריאייט פרוג'קט, לא ב-C-Sharp, האתגר היום הוא ב-C או ב-C++, 32, 32 וזה יהיה קריאייט שרד סאמפל 01, יצירה של שרד ונגיד לו אוקיי.

  2. 00:38

    אפליקיישן סטינג, MT כמובן, סליחה, בלי pre-compile ו-empty, נקי, נקי, נקי, קונסול, נקי וזהו ונגיד לו finish ואת זה אפשר לסגור, עכבר ימני ו-add new item ו-c++ זה ייקרא main רוצה בשפת c או ב-c++ לא משנה אז אם אני לא אומר כלום אז הוא יפסיק סיומת cpp והתוכנית הזאת תהיה ב-c++ אז בואו נגיד לו void,

  3. 01:19

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

  4. 01:35

    זה עובד, את זה אני אקטין, את זה אני אקטין, שיהיה ככה, עכבר ימני וproperties, לא עולה, כן, זה בעיה, זה בעיה, אז בואו נגיד לו get char, פתח סגור ובצע הוא לא מוכן והרת מחדש ו-no אז בואו נראה הוא לא מכיר את get char יפה מאוד אז איפה get char נמצאת אני חושב שהיא ב-stdio.h בואו נגיד לו צולמית include stdio.h והרת יפה נקטין אותו עכבר ימני וproperties

  5. 02:26

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

  6. 02:35

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

  7. 02:51

    התוכנית הראשית תחכה ל-enter והתוכנית המשנית ה-thread רק ידפיס למסך בתור התחלה. אז בואו אולי נתחיל מזה שנעשה פה לולאה. פור אינט איי שווה ל... שווה לאפס, איי קטן ממגיד איזה מספר, 10, 1, 2, 3, 1, 2, 3, 10 מיליון, ואיי פלוס פלוס ו...

  8. 03:24

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

  9. 03:37

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

  10. 03:52

    אז f1, נחכה ל msdn שיעלה לו אז הנה הוא מתחיל לעלות, יפה, סליפ, השאלה אם זו הסליפ הנכונה בואו נגיד, זה נראה לי שזה הסליפ הנכונה נגיד לו sink-slip שנמצא בפרוסס נפרד פונקצ'יינס בסיסטמפ סרוויסס אז דיקייט אוגומנטיישן זה נראה שזה בסדר בווין 32 ווין 32 זה בסדר גמור

  11. 04:23

    אז זאתי סליפה טובה יפה אז איפה נמצאת ההצהרה שלה זה אומר שההצהרה נמצאת או, header בווינדבייס, זאת אומרת declared in winbase.h אבל include את windows.h למרות שההצהרה נמצאת בווינדבייס.h אתה אבל תוסיף את windows.h כי זה מה שכדאי לעשות, אז בואו נשכפל את השורה

  12. 04:54

    הזו וזה יהיה windows.h ו-ctrl shift רווח, ctrl shift s, ctrl shift רווח, ctrl רווח, הוא עדיין טרנד שהוא לא מכיר אבל ctrl shift b, הוא עדיין לא מכיר, אה, סעיף 5 של does not take 0 ארגומנטים, יפה מאוד, אנחנו נעשה פה סליף של עשירית השנייה, אז 10 פעמים בשנייה אנחנו נשען, וכך תעבור לשנייה אחת, מה שאמור

  13. 05:25

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

  14. 05:48

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

  15. 06:30

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

  16. 06:53

    אז מה שאנחנו נעשה, פה אנחנו נקרא לפונקציה, בואו את זה נסגור, נקרא לפונקציה create thread, ובואו נראה מה הסיפור שלה. create thread, דבר ראשון מחזירה handle.

  17. 07:09

    אז נגדיר handle h, רגע, קודם כל הוא, אוח, כיבדתי אותו, עוד פעם. handle h thread שווה ל, יפה. זה ה-thread שאנחנו ניצור שמור ורווח security בלי security stack size בלי זאת אומרת הוא כבר יבחר את ה-stack size את גודל המחסנית ה-default אני חושב שזה 1 מגה בייט אז אם אני אומר לו 0 זה יהיה 1 מגה בייט וה-start

  18. 07:46

    address הכתובת של הפונקציה איפה אנחנו מתחילים אז הוא אומר פה שזה צריך להיות מסוג long pointer ל-thread start routine אוקיי אז בואו נראה איך זה אמור לראות פליק על זה ו-F12 אפשר גם ללכת ל-MSDN ולראות ב-MSDN איך זה אמור לראות אבל אפשר גם ללכת לפה ו-F12 ולראות איך פה זה אמור לראות זה

  19. 08:14

    אמור לראות כך אז הוא אומר שכאן אגב הוא עושה פה טייב דף למי שעובד בשפת C שהפוינטר לצרד סטארט רוטין זה גם LP אז לא קשור למי שעובד בשפת C זה פשוט מוסיף פה L לא חשוב מה שהוא אומר פה זה שהוא מגדיר את פוינטר לפרק סארט רוטין את האידנטיפה את המזהה הזה הוא מגדיר שזה מצביע לפונקציה שהיא מסוג win api win api f12 זה בסך הכל std

  20. 08:53

    call יפה הפונקציה מחזירה דאבל וורד ומקבלת כפרמטר void lp void f12 זה בסך הכל void far כוכבית מה זה far f12 far זה כלום יפה זאת אומרת void כוכבית, עוד פעם F12 זה בעצם LP void, זה בסך הכל void כוכבית.

  21. 09:17

    יפה מאוד, אז void כוכבית זה הפרמטר שהיא מקבלת. מה זה עוד פעם? אז היא double word, מחזירה את double word, היא מסוג winAPI והיא מקבלת void כוכבית.

  22. 09:31

    אז בואו נגדיר אותה, אז נשים אותה פה למעלה כדי שלא נצטרך גם להצהיר עליה. אז double word, קונטרול רווח enter, זה יהיה ה-thread pro, והיא מקבלת void כוכבית, אני אוהב לקרוא לזה state, את המצב.

  23. 09:59

    יפה. ובואו נשים פה breakpoint, ובואו, וקונטרול שיפט רווח, נשים פה את thread proc control רווח, והפרמטר כרגע יהיה 0, זאת אומרת מה שיועבר ל-state זה 0.

  24. 10:22

    מה עוד אנחנו יכולים להעביר ל-create thread? Creation Flags, תכף נראה אם צריך או לא צריך בינתיים להעביר 0 וLong Pointer ל-thread ID, מה המזהה של ה-thread?

  25. 10:36

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

  26. 10:51

    יפה. ובואו נראה מה עכשיו הולך לקרות. אז בואו נריץ את התוכנית. No, מה הבעיה? כן, איזה סגנון קיבל ברמת עזרי?

  27. 11:00

    From viewer to LP thread start routine. יפה, כי שכחנו, כן, cdcler. כרגע זה cdcler, והוא אומר שזה צריך להיות lp thread start routine שהוא win api, שהוא בעצם, אני הולך לתת לו win api, ה-f12 זה בעצם std call, נכון? זה מה שהוא אמר על עצמו.

  28. 11:25

    אני win api, אני std call. אני יכול להגיד פה win api, אבל אני תמיד מעדיף להגיד std call, יפה, ובצע, הוא לא אוהב את זה. זאת אומרת, פרוגמנס ריטורן ווליון, אז בואו נגיד לו לעת עתה ריטורן 0, ובצע, נחכה לו, יפה, וצור את ה־thread, והתחל, עכשיו ברור שעשינו סליפ, אז ה־thread התחיל לרוץ.

  29. 12:05

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

  30. 12:34

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

  31. 13:05

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

  32. 13:30

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

  33. 13:44

    יפה. כמובן שאני יכול גם להגיד לו ctrl+cv ולייצר עוד סרד. אני לא צריך כל כך את ההנדל הזה, נעזוב את ההנדל כרגע אז יהיה לנו create thread ומה שאני רוצה זה ש-core thread ידפיס משהו אחר אז בואו ב-state נעביר לו את האות ב-LP פרמטר פה נעביר לו אתה תדפיס a ואילו אתה תדפיס b והתוכנית עצמה מצידי לא תדפיס

  34. 14:20

    כלום היא תחכה ל-enter כדי להסתיים יפה אז ב-state אנחנו נקבל את האות אז char t שווה ל-casting ל-char של state. הבעיה שהוא מעביר void כוכבית, זאת אומרת, מבחינתו פה זה אמור להיות void כוכבית,

לקורס המלא: קורס C למתקדמים אונליין

ההרצאה הקודמת: הרצת שרת ושני לקוחות במקביל

ההרצאה הבאה: UltraVnc - Source Code compile

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

  • בעיית Cross Thread

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

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