עבור לתוכן

שאלה על Threading ב-VB .net

Featured Replies

פורסם

שלום לכולם, אני משתמש במחלקה שבכול פעם שהעכבר זז ממקומו

היא "מקפיצה" אירוע עם הפרמטר שמכיל את מיקום העכבר, בעיקרון

כאשר אני משתמש במחלקה באותו הליך של ה-UI הכול עובד כמו

שצריך ואכן כול פעם שהעכבר זז "מוקפץ" האירוע, הינה דוגמא של הקוד (הקוד לא נכון וכתבתי רק בשביל ההדגמה):


Dim WithEvents MHook as MouseHook
Private Sub Form_Load(Byval Sender as Object, SomeArgs) Handles Me.Load
MHook = New MouseHook()
End Sub


Private Sub Mouse_Moved(byval ptLocat as POINT) Handles MHook.MouseMoved
Debug.Writeline("Mouse Moved")
End Sub

ברגע שאני מכריז על המשתנה כ-New המחלקה אוטומטית מתחילה לעלות אירועים כשהעכבר זז, ביינתים הכול עובד

נפלא, ברגע שאני מריץ את התוכנה מופיע לי בשורת ה-Debug Mouse Moved וכאן מתחילה הבעייה: ברצוני לגרום לכך שהאירועים יוקפצו להליך שונה מההליך של ה-UI,

מה שחשבתי לעשות זה הדבר הבא:


Dim WithEvents MHook as MouseHook
Private Sub Form_Load(Byval Sender as Object, SomeArgs) Handles Me.Load
Dim t as New Thread(Addressof InstallHook)
t.Start()
End Sub

Private Sub InstallHook()
MHook = New MouseHook()
End Sub

Private Sub Mouse_Moved(byval ptLocat as POINT) Handles MHook.MouseMoved
Debug.Writeline("Mouse Moved")
End Sub

עכשיו ברגע שהכרזתי על המחלקה כמחלקה חדשה בהליך אחר ואני מריץ את התוכנה לא מתרחש כלום כשאני מזיז את העכבר -

מה שאני משער שקורה זה שלפי מה שאני מבין ההליך רץ, מתקין מכריז על המשתנה MHook כ-New וישר

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

גורם להליך לפעול בלי להיסגר ולתת למחלקה של ה-MouseHook "להקפיץ" אירועים להליך החדש?

פורסם

אתה מסתכל על זה לא נכון.

הת'רד בו אתה מאתחל את המחלקה MouseHook לא בהכרח קשור לת'רד בו היא מקפיצה את ה-Event.

להקפיץ בת'רד של ה-UI זאת דרך אחת(שדורשת שהאינסטנס של MouseHook יכיר את ה-GUI שלך באיזו שהיא צורה שמאפשרת Invoke).

בקיצור, זה תלוי במימוש של MouseHook. אך סביר להניח שהמחלקה מבצעת Invoke כזה.

(אפשר לבדוק את זה או באמצעות קוד, בהדפסה ב-Event של מאפייני הת'רד הנוכחי -- Thread.CurrentThread, או באמצעות הדיבגר(שמכיל חלון ת'רדס שאפשר להסתכל עליו אחרי שעצרת ב-Event))

כדי לקפיץ ארועים לת'רד חדש, אתה יכול להשתמש בדרך הנאיבית(לא יעילה אך פשוטה) של פתיחת ת'רד חדש על כול Event שקופץ.

או לפתוח ת'רד אחד ולהקרוא בו בו Queue של הודעות שתמלא בכול Event שקופץ, שים לב שבמקרה הזה אתה צריך לנעול את הקריאות ל-Queue(שימוש ב-SyncLock).

בכול אחד מהמקרים, כדי להשפיע בחזרה על ה-GUI תצטרך לבצע Invoke(שינוי ל-GUI חייב להתבצע בת'רד של ה-GUI).

פורסם
  • מחבר

שלום ותודה רבה על התשובה...!

הבנתי חלק מהשיטות שהצעת ואני יוכל להקל על יישום המשימה

שאני רוצה מפני שיש לי את קוד המקור של המחלקה ככה שאני

יוכל לשנות אותה כרצוני, וכניראה שצורת המחשבה שלי הייתה פחות טובה

מאשר לערוך את המחלקה עצמה. הסיבה העיקרית שאני רוצה לגרום לכך

שהמחלקה תתייחס להליך אחר היא בגלל שברגע שהתוכנה שלי

לא מגיבה למשך זמן מסויים ב-Windows 7 ה-Hook מתבטל (LowLevelHookTimeOut)

זאת בגלל שהתוכנה לא עיבדה את ההודעות (של תזוזת העכבר) במשך זמן מסויים.

אם מסתכלים על המחלקה (שצירפתי) ניתן ליראות כול ההודעות על תזוזת העכבר מעובדות בתוך המתודה MouseProc

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

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

[attachment deleted by admin]

פורסם

א. אתה יכול(וכנראה גם רצוי) למנוע מהת'רד הראשי שלך להתקע לזמנים ממושכים.

ב. בניגוד למה שאמרתי בהודעה הקודמת(הסתכלתי על התעוד של מיקרוסופט עכשיו), נראה שה-Event כן קורה בת'רד שמיצר את ה-Hook --

מה שאומר שהרעיון הראשוני שלך כנראה יעבוד. רק תדאג שהת'רד שאתה יוצר לא יצא(או ע"י sleep בלופ או ע"י יצירת Event כולשהו והמתנה עליו)

פורסם
  • מחבר

א. אתה יכול(וכנראה גם רצוי) למנוע מהת'רד הראשי שלך להתקע לזמנים ממושכים.

ב. בניגוד למה שאמרתי בהודעה הקודמת(הסתכלתי על התעוד של מיקרוסופט עכשיו), נראה שה-Event כן קורה בת'רד שמיצר את ה-Hook --

מה שאומר שהרעיון הראשוני שלך כנראה יעבוד. רק תדאג שהת'רד שאתה יוצר לא יצא(או ע"י sleep בלופ או ע"י יצירת Event כולשהו והמתנה עליו)

האם אין דרך יותר טובה לגרום ל-Thread לא להיסגר חוץ מלהכניס אותו לתוך לולאה? בעיקרון ממה שאני מבין

ברגע שההליך מסיים את המשימה שנתתי לו הוא ישר נסגר, אין איזה אפשרות יותר הגיונית (כמו תכונה מסויימת)

שגורמת להליך להמשיך לפעול למרות שסיים לבצע את מה שביקשתי ממנו?

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

נשמע הגיוני יותר שיש לו איזו תכונה ולא בדרכים כמו לולאות או Sleep, כי אם אני לא טועה הוא יתקע בהם.

פורסם

א. בעצם לא בטוח שאתה צריך להחזיק את הת'רד פתוח, רק תחזיק את ה-MouseHook כ-Member כדי שהוא לא ימחק ע"י ה-GC.

ב. אם זאת תוכנית WinForm יש לך Application.DoEvents שמבצע את ה-Events שממתינים.

פורסם
  • מחבר

מצטער על חוסר הידע ובאמת באמת תודה על העזרה, אך איך אני מחזיק אותו כ-Member? ומה זה אומר?

והפקודה Application.DoEvents היא לא רק ל-Thread של ה-UI?

פורסם

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

ב. כן.

פורסם
  • מחבר

החלטתי לבסוף להסיר את ה-Hook בכול פעם שאני מבצע פעולה שגורמת להליך של ה-UI לא להגיב ואחר כך

להחזיר את ה-Hook, וזה כניראה פתר את הבעיה - אבל נותרה לי שאלה נוספת ואחרונה,

האם יש אפשרות לדעת מתי ה-Hook הפסיק לשלוח הודעות? (בגלל המקרה שציינתי שההליך של ה-UI לא מגיב)

ארכיון

דיון זה הועבר לארכיון ולא ניתן להוסיף בו תגובות חדשות.

דיונים חדשים