فورم عبقري
عنوان الدرس : مقدمة في المهمات ( أو تعدد العمليات أو ثريد)
ملاحظة: يعتبر هذا الدرس مكمل لدرس الفورم السريع.
Thread ثريد أو مهمة
إصدارات فيجوال بيسك القديمة كانت تدعم المهمات بشكل محدود. أما فيجوال بيسك دونت نت فإنها تتيح للمطورين قوة كاملة في استخدام المهمات. إن استخدامك المهمات بشكل صحيح يزيد من أداء تطبيقك ويجعله أكثر تفاعل.
ما هي المهمة
أي تطبيق شغال (Running) على جهاز الحاسب يعتبره الحاسب معالجة (Process) وكل معالجة حتى تنتهي تحتاج إلى مهمة أو أكثر. ثريد أو مهمة هي وحدة ( (unitتنفيذية يتم معالجتها بواسطة المعالج.
كيف يقوم المعالج CPU بمعالجة مهمة
يستطيع المعالج أن يعالج مهمة واحدة في نفس اللحظة لذلك هناك مجدول مهمات خاص يدعى Thread Scheduler والذي يحدد الوقت الذي يحتاجه المعالج لكل مهمة لإنهائها بشكل تام قدر الإمكان قبل أن يسمح لمهمة أخرى بالوصول إلى المعالج. هذه الجدولة تجعل الحاسب يظهر كأنه يعالج أكثر من عملية في نفس الوقت.
في الواقع الذي يحصل هو التالي:
1. كل ثريد أو مهمة تحتوي بداخلها على صف استدعاء (call stack) ومخزن (storage) للمتغيرات ويذهبان مع كل مهمة ذاهبة إلى المعالج عندما يأتي دورها المحدد في المجدول.
2. عندما ينتهي الوقت المحدد للمهمة يقوم المجدول بإزالتها من المعالج.
عندما يعمل على الجهاز تطبيقات كثيرة في نفس الوقت فهذا يعني مهمات كثيرة ستنفذ على الجهاز وسيؤدي ذلك لتراكم مهمات كثيرة في المجدول. وهذا ما يفسر لنا بطئ الجهاز عند فتح أكثر من تطبيق في نفس الوقت وجميعها تحتاج لمعالجة.
هناك نوعان من المهمات ، مهمة فردية (Single Threading) ومهمات متعددة (Multithreading). المهمة الفردية كانت في الإصدارات القديمة من فيجوال بيسك بحيث لا تستطيع أن تجعل التطبيق ينفذ أكثر من عملية في نفس الوقت ، أما المهمات المتعددة فهي مدعومة في فيجوال بيسك دوت نت بحيث يستطيع التطبيق أن ينفذ أكثر من عملية في نفس الوقت دون انتظار العملية السابقة حتى تنتهي.
فوائد تعدد المهمات Advantage of Multithreading
1. تحسين سرعة استجابة واجهة المستخدم
يمكنك استخدام أكثر من ثريد لإنجاز معالجة واحدة وذلك لتحسين مدى استجابة واجهة المستخدم. مثلا
• استخدم المهمات في العمليات التي تحتاج وقت طويلة لمعالجتها، مثل التدقيق الإملائي والذي يوجد مع برنامج الورد. وستلاحظ أنه يعمل في الخلفية بينما أنت تقوم بالكتابة وبدون أن يعيقك أثناء الكتابة.
• حدد لكل مهمة مستوى الأفضلية بحيث تعطي المهمات ذات الأهمية أفضلية أعلى من المهمات الأخرى التي تحتاج أفضلية منخفضة. فالتطبيقات التي تمتلك تفاعل كبير مع المستخدم يجب أن تعطي أفضلية عالية للمهمات التي تخص واجهات الاستخدام.
2. التخلص من الإعاقة No Blocking
الإعاقة تحدث عندما يتم استدعاء تطبيق لا يدعم تعدد المهمات فإنه يجب الانتظار حتى يتم إنهاء أي استدعاء سابق قادم من جهاز آخر على الشبكة. في التطبيقات التي تخص السيرفر الإعاقة سوف تحدث عندما تتزامن عدة أجهزة بالطلب من السيرفر بينما فقط مسموع بمهمة واحدة.
التطبيقات التي تدعم تعدد المهمات قادرة على إنجاز طلبات لمهمات مختلفة في نفس الوقت بدون الانتظار لإنهاء أي مهمة. هذا يسمح بمعالجة طلبات عدة أجهزة على الشبكة في نفس الوقت.
بناء مهمة Constructing the Thread
ثريد كلاس
استخدم ثريد كلاس (System.Threading.Thread) لإنشاء مهمات متعددة.
عندما يتم قدح مهمة فإن المعامل AddressOf يقوم ببناء المهمة ويحدد الطريقة التي ستنفذ بها كالتالي:
Dim th As New Threading.Thread(AddressOf PerformTask) ... Sub PerformTask( ) ... End Sub
منهجيات المهمات Threading Methods
كلاس مهمة (Thread class) يتيح عدة منهجيات للتحكم في معالجة المهمة.
Start: ابدأ تنفيذ المهمة
Abort: إنهاء تنفيذ المهمة
Sleep: تجميد المهمة لمدة معينة ويتم تحديد عدد الـ (milliseconds) المطلوبة وإذا كانت تساوي صفر أصبحت المهمة تشبه DoEvent والتي تتيح فرصة إنجاز مهمة واحدة ثم الرجوع للمهمة الأصلية.
Suspend: توقف مؤقت لتنفيذ المهمة.
Resume: إعادة تفعيل مهمة موقفة مؤقتا.
خصائص المهمة Threading Properties
هناك خاصيتين الأولى لمعرفة حالة المهمة والثانية لتحديد أفضلية المهمة.
ThreadState: لمعرفة الحالة الحالية للمهمة (Running, Suspend, Aborted )
Priority: لتعديل مستوى الأفضلية في تنفيذ المهمة بإعداد الخاصية Priority بواسطة ThreadPriority والذي يأخذ أحد القيم التالية:
AboveNormal, BelowNormal, Highest, Lowest,and Normal
تنبيه: إذا قمت بتحديد ThreadPriority إلى Highest هذا ممكن يؤثر على حيوية النظام لأنك ستمنعه من عمل أي شيء آخر. استخدم هذا الاعداد بحذر شديد.
مثال لإنشاء مهمة مع إختبار الحالة وتغيير الأفضلية
Dim th As New Threading.Thread(AddressOf PerformTask) th.Start( ) If th.ThreadState = ThreadState.Running Then th.Priority = Threading.ThreadPriority.AboveNormal End If
متى نستخدم المهمات When to Use Threading
استخدام المهمات مفيد ولكن استخدامها بشكل خاطئ ممكن يسبب مشاكل في الأداء ، حدوث تعارض في البيانات ومشاكل أخرى.
مصادر النظام System Resources
المهمات تستهلك الذاكرة والمصادر الأخرى مثل وقت المعالجة لذلك استخدام مهمات كثيرة يتطلب مصادر نظام أقوى. إذا كان هناك عدة تطبيقات تعمل معا وتستخدم المهمات بشكل مفرط فهذا سيؤدي للبطئ لأن معظم وقت المعالج سينقضي في عملية التبديل بين مهمة وأخرى.
المصادر المشتركة Shared Resources
عندما أكثر من مهمة تريد الوصول لنفس البيانات والتعديل عليها في نفس الوقت عند ذلك سيحدث تعارض في البيانات أو قد تنتج نتائج خاطئة. فمثلا لو عندنا مهمتين A و B وكلاهما تستخدمان مصدر بيانات مشترك كمتغير صحيح يحتوي القيمة 10. الآن قامت المهمة A بقراءة القيمة 10 من المتغير وبدأ بتنفيذ عمليات حسابية طويلة وأثناء ذلك قامت المهمة بالتعديل على القيمة إلى 15. عند ذلك ستنتج نتائج غير صحيحة. والحل هو استخدام منع التزامن SyncLock
تزامن المصادر المشتركة Synchronizing Shared Resources
يمكن منع تغير بيانات المصدر في فترة المعالجة التي تحتاج فيها عدم تغيير بيانات المصدر من قبل مهمة أخرى وذلك باستخدام جملة SyncLock. أنظر المثال التالي:
المثال التالي يعرف مصدر مشترك اسمه SharedReference وهو عبارة عن متغير صحيح. الكلاس ThreadObj سينفذ من قبل أكثر من ثريد. وقد استخدمنا في الكلاس منع التزامن SyncLock ليقوم بقفل مصدر البيانات المشترك عندما يكون تحت الاستخدام. الكود التالي يوضح هذا السلوك. حيث أن هناك مهمتان ستعملان بشكل متتالي وتستخدمان نفس مصدر البيانات SharedReference .
Imports System.Threading 'Shared data Public Class SharedReference Public Id As Integer End Class 'Class for running on other threads Public Class ThreadObj Private sr As SharedReference Private Count As Integer 'Constructor with reference and Id Public Sub New(ByRef sharedRef As SharedReference, _ ByVal ID As Integer) sr = sharedRef Count = ID End Sub 'Actual worker method Public Sub RunMethod( ) SyncLock (sr) 'Lock sr object sr.Id = Count 'Execute lengthy code 'sr.Id could have changed without SyncLock Count = sr.Id End SyncLock 'Release sr object lock End Sub End Class Module MainModule Sub Main( ) 'Create shared data object Dim sr As New SharedReference( ) 'Create two worker objects Dim worker1 As New ThreadObj(sr, 1) Dim worker2 As New ThreadObj(sr, 2) 'Create two threads Dim t1 As New Thread(AddressOf worker1.RunMethod) Dim t2 As New Thread(AddressOf worker2.RunMethod) 'Start both threads t1.Start( ) t2.Start( ) End Sub End Module
أنظر المثال المرفق.
أيضا الشرح مرفق في ملف وورد للوضوح.


