threads

yaron881

New member
threads

לא יצא לי לעבוד עם threads וניסיתי לעשות לצורך הלימוד משהו פשוט.
ב-winform לשים כפתור שבלחיצה עליו, יפעיל לופ אשר בכל איטרציה שלו ירשום את הערך בלייבל בטופס.
זה מה שכתבתי:
private void button1_Click(object sender, EventArgs e) {
for (int i = 0; i < 1000; i++)
{ ParameterizedThreadStart start = new ParameterizedThreadStart(writeText); Thread thread = new Thread(start); thread.Start(i); } } private void writeText(object a) { string content = a.ToString(); SetTextBoxText(content); } private void SetTextBoxText(string content) { MethodInvoker invoker = new MethodInvoker(delegate { label1.Text += content + " "; }); label1.Invoke(invoker); }
כנראה שאני עושה משהו לא נכון, כי זה לא מדפיס את הערך של i עד לסיום הלופ
 

Miki Watts

New member
זה שאתה קורא ל Start של ה Thread לא אומר שזה יתחיל לעבוד

מיידית. כל עוד אתה בתוך הלולאה, הקוד שלך לא מטפל ב Message Pump שאחראית להפעיל אירועים ו threads חדשים, ולכן רק ביציאה מהפונקציה אתה תראה את התוצאה הסופית.
&nbsp
בכל מקרה, מה שאת נופל עליו זה מכיוון שכאשר אתה קורא ל Start של ה thread, וכאשר ה thread יתבצע בפועל, כפי שכתבת את זה המשתנה i הוא למעשה מצביע לערך הנוכחי של i, ולא לערך שהיה לו בזמן אתחול ה thread. (צריך להבין מה .net עושה למעשה מאחורי הקלעים: הוא מייצר delegate ומעביר אליו reference למשתנה, ולא עותק של המשתנה). אתה יכול לראות את זה אם תשים breakpoint בהפעלה של ה thread עצמו ותראה איזה ערכים של i אתה מקבל.
הדרך לפתור את זה היא להעתיק את i למשתנה מקומי בתוך הלולאה, ואז את אותו משתנה מקומי להעביר ל thread, כך שאותו delegate למעשה יקבל reference למשתנה המקומי עם הערך הנוכחי שלו, וכל thread יעבוד עם ערך שונה.
 

Royi Namir

New member
למיטב הבנתי , זו לא הבעיה כאן

Had he did :

ParameterizedThreadStart start = new ParameterizedThreadStart(writeText); Thread t = new Thread(() => writeText(i));
t.Start();
Then you would be right.

e.g. :
http://i.imgur.com/17hNQkY.png


And the result would be missing the right value , and as you've said , the solution would be :
ParameterizedThreadStart start = new ParameterizedThreadStart(writeText);int i1 = i;
Thread t = new Thread(() => writeText(i1));
t.Start();
Result:
http://i.imgur.com/oi7dsvA.png


AFAIKS - He has no problem here.
The thread.Start(i) already (not)capture the variable.
it's just that the order is not sequentially.

A 500 threads test : http://i.imgur.com/w8OhJOr.png
 

yaron881

New member
נראה לי שלא הסברתי נכון או

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

אני מקבל את כל המספרים בסוף הלופ , ובזמן שהלופ רץ החלון קפוא

 

Miki Watts

New member
אוקי, אז אם ככה זה הדבר הראשון שהזכרתי

דרך מיידית לראות אם זה אכן הבעיה, זה להכניס Application.DoEvents() בכל סבב של הלולאה. זה אמור לאפשר ל GUI לרענן את עצמו.
&nbsp
אבל!!! זה לא פתרון קבוע, זה לא משהו שאמורים להשתמש בו ויש מצבים מסויימים שזה יגרום לבעיות מפה ועד הודעה חדשה.
מה שאתה רוצה לעשות במצב כזה, זה להתחיל thread אחד, לאפשר ל GUI להמשיך בריצה, ואותו thread יתחיל להריץ את הלולאה של ה threads האחרים.
 

Miki Watts

New member
תאתחל thread, תן לו בתור פונקציה את הפונקציה שיש לך כרגע

ותן לקוד להמשיך בריצה לאחר מכן
 

Miki Watts

New member
לא, בלחיצה על הכפתור אתה מאתחל 1000 threads בתוך לולאה

כל עוד אתה בתוך הלולאה, המסך לא יתעדכן.
 

spiritus asper

New member
תעשה לעצמך טובה

אם הכוונה היא ללמוד Threads, אל תתחיל מאפליקציות UI.
אפליקציית Console תעשה את העבודה. אחר כך תוכל להתפנות להבין למה התופעות האלו קורות ב-UI.
 

spiritus asper

New member
זאת הנקודה

אם אתה רוצה ללמוד Threads מהבסיס, ההתעסקות הזאת רק תוסיף רעש בשלב הזה.
 

yaron881

New member
התחלתי מקונסול ושם הסתדרתי ולא נתקלתי

בהשלכות שיישום winform מעלה
 

rondadon1985

New member
כי שם אין את הנושא של Thread של הGUI

מכיוון שאתה השתמשת בלולאה שיוצרת 1000 ת'רדים בתוך הת'רד של הGUI,
העידכון של הGUI "קפא" עד שהלולאה הזו הסתיימה.
&nbsp
לא ברור לי אם הבנת מה שהסבירו לך למעלה, אבל למקרה שלא, הכוונה היתה שאתה יוצר ת'רד בודד, שבתוכו אתה מריץ את הלולאה שיוצרת את כל שאר הת'רדים. ככה אתה משאיר את הת'רד של הGUI לעשות את מה שהוא צריך (לעדכן את הGUI) וממשיך להריץ ברקע את הלולאה מבלי להפריע לו.
&nbsp
&nbsp
 
למעלה