שאלה בנוגע ל thread

ronitV

New member
שאלה בנוגע ל thread

התכנית
#include <conio.h> #include <stdio.h> #include <process.h> int repeat = 1; void OutputThread(void* pArguments) { while(repeat) { printf("*"); } } void InputThread(void* pArguments) { char ch = getch(); repeat = 0; // for stopping } int main() { _beginthread(InputThread, 0, NULL); _beginthread(OutputThread, 0, NULL); //_endthread(); return 0; } עכשיו לא ברור לי היכן למקם את ה
_endthread​
והאם לכל beginthread צריך endthread משלו ואם כן אז איך לשייך ל thread מסויים ?
 

vinney

Well-known member
קצת הגיון בריא

אם beginthread מקפיץ את התהליכון החדש שנוצר לכתובת שהעברת לו, אז ה endthread המתאים לו צריך להיות ברצף המבוצע החל מהכתובת הזאת, לא ברצף בו מבוצע הbeginthread.
 

ronitV

New member
אבל

למשל במצב הזה
void OutputThread(void* pArguments) { while(repeat) { printf("*"); } _endthread(); }​
התכנית לא תדפיס אפילו תו אחד (בניגוד למה שניתן לחשוב)
 

vinney

Well-known member
ברור שלא. לא ניתן לחשוב גם.

אני לא יודע למה את חושבת שהיא אמורה להדפיס משהו... שימי לב, שאת יוצאת מהתוכנית (main) מיד עם יצירת הthreadים שלך, למעשה הם עוד לא מספיקים להווצר אפילו. לכן התוכנית לא מספיקה להדפיס כלום. אגב, את _endthread לא ממש חייבים לכתוב, כי הוא מבוצע אוטומטית עם היציאה מהפונקציה אותה שלחת כפרמטר לbeginthread.
 

ronitV

New member
OK

אז מה שאני מבינה זה שלא לכל beginthread חייב להיות endthread - אלא אם רוצים לגרום לסיום במצב מסויים.
 

vinney

Well-known member
גם זה לא

מספיק לעשות return. לאחר החזרה לbeginthread (שממילא קורה עם היציאה מהפונקציה) תמיד מתבצעת קריאה ל endthread.
 

ברנדל

New member
תמחקי את endthread מהלקסיקון

לא משתמשים בזה אף פעם! EndThread נועד להרוג thread בצורה ברוטלית מתוך ה thread. TerminateThread נועד לעשות אותו דבר (ברוטלית) מחוץ ל thread. בשניהם אסור להשתמש אלא במקרים קיצוניים מאוד. למה? כי את לא נותנת ל thread הזדמנות לנקות את עצמו בצורה מסודרת כמו שהתכוונת. לדוגמא: נניח שבתוך ה thread יצרת אוביקט שיש לו destructor. ה destructor לא יקרא כי את החלטת לצאת מה thread לא בצורה מסודרת אלא קטעת אותו באמצע. אם את רוצה לצאת ממשהו באמצע הפתרון הנכון הוא break בלולאה וסיום ה thread בצורה טבעית. הפונקציות הנ"ל אינם בשימוש בתכנות מקצועי.
 

selalerer

New member
אני לא הבנתי למה. ../images/Emo163.gif

הוא לא נשאר "תקוע" בלולאה עד שאתה מאפס את הrepeat ורק אז מגיע לendThread? אנא האירו את עיניי.
 

vinney

Well-known member
זה אלמנטרי, וואטסון

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

selalerer

New member
אהה, את זה הבנתי....

....אבל חשבתי שיש משהו שקשור לקוד שהוא כתב עבור הthread.
 

ברנדל

New member
לא עושים את זה ככה

אל תמקמי את ה endthread בשום מקום ואל תשתמשי בו אף פעם. בתוך ה main לפני היציאה תרשמי WaitForSingleObject זה API של windows שבקונוטציה הנוכחית את אמורה להעביר לו כפרמטר את ה handle שקיבלת כתוצאה מ _beginthread. הפונקציה מחכה בדיוק עד שה thread מסתיים. הפונקציה תוקעת את ה thread של ה main עד שה Thread מסתיים. במקרה ואת מפעילה מספר threads עלייך להשתמש ב WaitForMultpleObject. ולהעביר מערך של handles. ה thread מסתיים מעצמו (כשהוא יסיים את הrepeats ) וכשהוא יסתיים הפונקציה waitforsingleobject תסיים לחכות וה main יעבור לשורה הבאה.
 

voguemaster

New member
ומה בנוגע ל-detached threads ?

לא בכל מצב אתה צריך מודל של thread שממתין לסיום של thread אחר.
 

vinney

Well-known member
זה קצת בעיה

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

voguemaster

New member
לא רק

מצב בסיסי מאוד של concurrent server שמשתמש ב-threads. זה DESIGN בסיסי (אולי בסיסי מדי
). השרת עצמו לעולם לא יוצא (בתיאוריה, אלא אם כן קורה משהו מוזר או שיש באג
) אבל ה-threads כן. כמובן שהשלב היותר מוצלח הוא להשתמש ב-thread pool.
 

DarkSwell

New member
תשובה פשוטה,

בעיקרון מתבצעת קריאה אוטומטית ל endthread מהפונקציה ש beginthread קיבלה כארגומנט ראשון, אחרי היציאה מאותה פונקציה. אך כדי להיות בטוחים ניתן בכל זאת להוסיף את הקריאה ל endthread בסוף הפונקציה(בדוגמא שלך ב OutputThread ו nputThread).
 
למעלה