[مقال] Make Thread-Safe Calls to Windows Forms Controls - نسخة قابلة للطباعة +- منتدى فيجوال بيسك لكل العرب | منتدى المبرمجين العرب (http://vb4arb.com/vb) +-- قسم : قسم لغة السي شارب C#.NET (http://vb4arb.com/vb/forumdisplay.php?fid=175) +--- قسم : قسم مقالات C#.NET (http://vb4arb.com/vb/forumdisplay.php?fid=177) +--- الموضوع : [مقال] Make Thread-Safe Calls to Windows Forms Controls (/showthread.php?tid=1458) الصفحات:
1
2
|
Make Thread-Safe Calls to Windows Forms Controls - الشاكي لله - 05-01-14 السلام عليكم ورحمة الله وبركاته
{Make Thread-Safe Calls to Windows Forms Controls} {كيف تصل الى الفورم وادواته من خلال Thread} --
اليوم سنتحدث عن شيئ مهم وهو واجه او سيواجه اي مبرمج ، حقيقة قد طلب مني الاخ عبد الرحمن وضع هذه المقالة لأنه يعتقد انه لايزال الكثيرون يجهلون هذا الموضوع او قد يجهلون الThread اساسا ، بصراحا قد وضعت العنوان باللغة الانجلينزية لاني لم اجد ترجمة مناسبة لهذا العنوان .. فالافضل ان تبقى بعض المسميات على حالها . اقسام المقالة
* نظرة سريعة عن الThread
* لماذا Thread-safe * CheckForIllegalCrossThreadCalls * استعمال Invoke وال Delegate لعمل Thread-Safe Calls * مقارنة بسيطة ( Invoke Vs BeginInvoke ) * المراجع & الخاتمة نظرة سريعة عن الThread
الThread هو مسار تنفيذ ويلزم وجوده في اي برمجية في العالم ، فكل برنامج في العالم يحتوي على ثريد رئيسي . دعنا نشبه ال Thread بالمسار في الشارع كما نعلم ان الشارع له مسارات (1 , 2 , 3 ...) حتى في الHighway تجد 4 مسارات او اكثر ، تخيل ان في الHighway يوجد مسار واحد فقط مالذي سيحصل ؟؟؟ النتيجة الطبيعية لهذا السؤال = ازدحام مروري والموضوع نفسه يحصل في البرمجة ، لو انشأت دالة باسم DownloadFile وقمت بتنزيل ملف حجمه 1 غيغا بايت ، مالذي سيحصل ؟؟؟؟ لاحظ الصورة :- فالوضع هنا مثله كمثل سيارة تمشي ببطأ وتعطل مسار السير في الشارع ، فالدالة DownloadFile ستأخذ وقت ريثما يتم تنزيل الملف ، في المقابل سيحصل للفورم Not Response ولايمكنك عمل اي شيئ فيه ، فهل ستقبل ان يحصل هذا للمستخدم ؟؟؟ اذن لماذا Internet download manger لايتعطل وهو يقوم بتنزيل الملفات ؟ نعم ، لانه يستعمل مسار اخر( Thread )لتنفيذ دالة Download File ، وهكذا اصبح لدينا مسارين :- 1- المسار الرئيسي UI thread 2- المسار الفرعي الذي يحتوي على دالة Download File وهكذا السيارة البطيئة ستمشي في مسار لوحدها ولن تعطل المسار الرئيسي الفريم وورك قد خصص لنا Namespace كامل للتعامل مع الThread . بشكل عام، يمكنك انشاء ثريد فرعي بكل سهولة :- PHP كود : private void button1_Click(object sender, EventArgs e) انا لن اشرح ال Thread اكثر من ذلك ، فهناك دروس كثيرة تتحدث عنه ، فأتمنى منك رؤيتها وتطبيقها كي تفهم القادم بشكل افضل لماذا Thread-safe ؟
ماهو الThread-safe call اصلا ؟؟ عندما تحاول اسناد قيمة لاي اداة على الفورم او حتى اسناد قيمة للفورم نفسه وذلك من خلال الThread الفرعي سيعطيك المترجم خطأ وهو خطأ مشهور :- هذا الوصول يعتبر Unsafe-Thread call وهذا الوصول يتم منعه افتراضي لأن الTextbox تم انشائها في Thread أخر وهو طبعا الثريد الرئيسي (UI thread) ، لماذا تم منعه وما الحكمة من ذلك ؟؟ Unsafe-Thread call له مخاطر جمة وعلى اثرها سيتدمر برنامجك ، سيحصل عدم استقرار للأداة ، وسيحصل bugs (اخطاء) تتعلق بالثريد ، وايضا قد تدخل الاداة في حالة جمود دائم . لهذا افتراضيا تم منع Unsafe-Thread call ولذلك اذا كنت تريد الوصول الى الاداة من خلال الثريد يجب عمل وصول آمن لها Thread-safe call CheckForIllegalCrossThreadCalls
هذه خاصية معروفة للفورم وهي تقبل قيمة بولينية (True | False) ، ما وظيفة هذه الدالة ؟؟ جعل هذه الخاصية False يمنع ظهور خطأ Cross-Thread وهكذا يعتقد البعض انها حل لخطا Cross-thread ، لكن هذه الخاصية ستسبب لك مشاكل اكبر من ذاك الخطأ ، فجعل هذه الخاصية false تعني "إلغاء فحص الاستدعائات الغير شرعية" .. قلنا سابقا ان المترجم يفحص اذا كان هناك وصول Unsafe ويقوم باظهار خطأ ، ولكن جعل هذه الخاصية false يمنع المترجم من البحث عن الوصولات الغير أمنة . وبذلك فنحن قمنا بالاحتيال على المشكلة ولم نقم بحلها ونتيجة لذلك .. إقتباس :No, that's not safe. The Winforms code that checks for threading mistakes is very important, the trouble that causes is extremely hard to diagnose. The biggest problem is that it doesn't cause consistent failure, your app will misbehave randomly and deadlock or crash only once a month. Or never at all, until you make a minor change. Or only on a particular user's machine, you'll blame the user instead of your code. ببساطة قد يتحطم برنامجك (Crash) او يصبح سلوكه غير معروف ويقوم بفعل اشياء على هواه او قد يدخل في حالة جمود . السبب الوحيد لوجود خاصية CheckForIllegalCrossThreadCalls هو للتوافق مع NET 2.0 واعلى (صراحة لم افهم المقصود من كلامه جيدا) المهم كيف سنجعل الوصول آمن ؟؟ هذا ماسنتطرق اليه من هنا الى نهاية المقالة . استعمال Invoke وال Delegate لعمل Thread-Safe Calls
الدالة Invoke وهي موجودة في جميع الControls ، ووظيفتها هي تنفيذ كود على الThread الذي قام بإنشاء هذه الControl ، وهي توجد ايضا للفورم وهكذا سنستخدم ال Invoke الخاصة بالفورم فقط لأنها طبيعيا تؤدي الى نفس الثريد الذي قام بإنشاء الControls . وطريقة فعل ذلك :- PHP كود : this.Invoke((MethodInvoker)delegate الكود كامل :- PHP كود : private void button1_Click(object sender, EventArgs e) الان لن يعترض عليك المترجم وسيصبح برنامجك في أمان لأن هذا الوصول يعتبر Thread-Safe كيف تستخدم Invoke :- Invoke تريد بارمتار عبارة عن مفوض (Delegate) يشير الى الدالة التي تريدها ان تتنفذ في الثريد الرئيسي ، وانا بدل ان اقوم بتعريف Delegate جديد فقد استخدمت (MethodInvoker) وهي Delegate جاهزة . يبقى السؤال لماذا استخدمت الكلمة المفتاحية delegate ؟؟ السبب هو اختصار الكود لاأكثر ، فdelegate هي كلمة مفتاحية لتعريف دالة مجهولة (بدون اسم) ، ولكن لن يضر لو استخدمت الطريقة التقليدية :- PHP كود : void DonwloadFile() ولكن الافضل استخدام دالة مجهولة فهي اسرع ومختصرة اكثر . مقارنة بسيطة ( Invoke Vs BeginInvoke )
Invoke و BeginInvoke دالتان تؤديان نفس الوظيفة فا
Invoke : تنفيذ دالة الDelegate على الثريد الرئيسي وانتظارها حتى تنتهي BeginInvoke : تنفيذ دالة ال Delegate على الثريد الرئيسي وعدم انتظارها حتى تنتهي لنظرب مثالا بهذا الكود :- PHP كود : void DonwloadFile() في هذا الكود سيتم اظهار الرسالة بعد مرور ثانيتين ، لان الdelegate لم ينتهي قبل مرور ثانيتين فأنا وضعت (System.Threading.Thread.Sleep(2000 لتأخير اكتمال الDelegate اذن Invoke لا تذهب للأكواد التي بعدها اذا الdelegate لم ينتهي في حالة BeginInvoke سيتم اظهار الرسالة فورا ، فلن يتم انتظار الdelegate حتى ينتهي بل سيتم اكمال الاكواد التي تحت BeginInvoke بالتوازي مع الdelegate المراجع & الخاتمة
How to: Make Thread-Safe Calls to Windows Forms Controls
C# CheckForIllegalCrossThreadCalls What's the difference between Invoke and BeginInvoke آمل اني قد وفقت في سرد المعلومة بشكل صحيح ، وايضا كل الي ذكرناه ماهو الى القليل فقط عن الThread فهو بحر واسع . على العموم ، موفقين شباب تحياتي - Done by Alshaki LLah RE: Make Thread-Safe Calls to Windows Forms Controls - mamas1 - 05-01-14 موضوع منظم و جميل ما شاء الله عليك شكرا جزيلا لك أخي محمد على تلبيتك لطلبي .. أتمنى لك التوفيق و السداد في حياتك دائما. و بهذا تكون أول مرجع عربي على ما أعتقد عن هذه الخاصية مبروك RE: Make Thread-Safe Calls to Windows Forms Controls - الشاكي لله - 05-01-14 (05-01-14, 06:23 PM)mamas1 كتب : العفو حاضرين .. ماهو المرجع الاول . ولكن اعتقد اني وضحت بشكل موجز فقط RE: Make Thread-Safe Calls to Windows Forms Controls - Sajad - 05-01-14 السلام عليكم بارك الله فيك وجزاك الله خيرا تحياتي RE: Make Thread-Safe Calls to Windows Forms Controls - Abu Ehab - 12-12-14 بـــــــــــارك الله فيـــــــــــــك .. للعلم : بنتعامل في الشركة بنفس الطريقة التى شرحتها أنت , منذ سنوات .. وهي فعاله . يعطيك العافيه . RE: Make Thread-Safe Calls to Windows Forms Controls - ابو ابراهيم - 13-12-14 مرحبا [b]الشاكي لله و مرحبا بكل الموجودين مقال جميل وحقيقة ايرادك لمثال السيارة البطيئة ازاح بعض الغموض والغشاوة عن الأعين [/b] اخي اذكر انه كان يوجد مثال للاخ رامي لوف ولا يحضرني الاسم لذلك المثال المهم انه قام بتطبيق عملي على ال Thread والحقيقة انه التبس الامر علي حينها الى اليوم وها هو الان قد جاء الوقت لكي احاول ان استدرك ما فاتني اخي [b][b]الشاكي لله[/b] حبذا لو تدعمنا بمثال عملي بسيط بالمصدر يوضح الفروقات بين [/b] Thread Thread-safe وكل التوفيق للجميع واخيرا شكرا لك على هالموضوع المهم RE: Make Thread-Safe Calls to Windows Forms Controls - nani49 - 11-02-16 زادك الله علما وبارك لك فيه ارجوا ان تتطرق لكل جوانب لغة السي شارب نريد ان نكون محترفين على يدك هههههه ان شاء الله RE: Make Thread-Safe Calls to Windows Forms Controls - سعود - 08-07-16 ياجماعة الخير لقد جربت الكود PHP كود : Me.Invoke(New MethodInvoker(AddressOf Me.some)) PHP كود : Private Sub some() RE: Make Thread-Safe Calls to Windows Forms Controls - الشاكي لله - 08-07-16 ^ دالة some في الاعلى من الخطأ استدعائها بواسطة Invoke لان فيها loop وتاخير .. عليك بعمل Invoke فقط للاكواد التي تتعامل مع الForm واداوته ، وهي في كودك :- Label1.Text = a ProgressBar1.Value = a بامكانك لصق هذين الكودين في دالة جديدة مثلا (UpdateForm) وثم استدعاء UpdateForm بواسطة Invoke او الطريقة الافضل هي وضع الكودين في دالة مجهولة عشان تقدر توصل للبارمترات بسهولة :- PHP كود : Private Sub some() تذكر ، الدالة اعلاه قم باستدعائها بشكل طبيعي وليس باستعمال Invoke RE: Make Thread-Safe Calls to Windows Forms Controls - سعود - 08-07-16 بارك الله فيك ماهو كود التحقق ان الـ th مثلا قيد العمل. مثل if backgroundworker is busy |