هذا هو الموضوع الثاني من سلسلة مواضيع متعلق بالمسارات Thrading أقوم حاليا بالعمل على ترجمتها ولكن الترجمة ليست حرفية إنما أقوم بإضافة بعض التعديلات عليها حسب رؤيتي للموضوع وأرجو أن يوفقني الله لإكمال العمل حتى النهاية خدمة لأعضاء المنتدى فالموضوع كبير جدا وسيأخذ وقتا طويلا
بسم الله أبدأ
The SyncLock Statement
خلال زمن التشغيل لا يوجد شئ يضمن لك أن يسير الكود بشكل نظامي بدون مقاطعات وتكون عملية التشغيل بدون مقاطعات عملية قاسية على نظام التشغيل وخاصة عندما يكون عبارة عن بيئة متعددة المهام وفي معظم الحالات التي ستحتاجها ستكون قانعا بالدقة ضمن البرنامج الواحد وذلك عند معالجة الكود فعلى سبيل المثال يكون كافيا لك ضمان أن مسار تنفيذ واحد ضمن التطبيق الحالي يستطيع تنفيذ قطعة معينة من الكود في وقت محدد ويمكنك تحقيق ذلك بتضمين قطعة الكود تلك ضمن كتلة SyncLock…End SyncLock والذي يحتاج إلى متغير كمحدد له محققا المتطلبات التالية:
• يجب أن يكون مشترك بين جميع المسارات ويكون في العادة متغير على مستوى الفئة وبدون الخاصية ThreadStatic
• يجب أن يكون من نوع مرجعي مثل String أو Object واستخدام أنواع القيمة ينتج عنه خطأ في الترجمة
• يجب أن لا يحتوي على القيمة Nothing وفي حال تمرير القيمة Nothing سيسبب أخطاء في زمن التنفيذ
وفيما يلي مثال عن كتلة SyncLock
' The lock object. (Any non-Nothing reference value will do.)
Private consoleLock As New Object()
Sub SynchronizationProblem_Task(ByVal obj As Object)
Dim number As Integer = CInt(obj)
' Print a lot of information to the console window.
For i As Integer = 1 To 1000
SyncLock consoleLock
' Split the output line in two pieces.
Console.Write(" ")
Console.Write(number)
End SyncLock
Next
End Subوالكود السابق يستخدم المتغير consoleLock للتحكم بالوصول للغرض Console وهو يشكل المصدر الوحيد المشترك بين جميع المسارات في المثال ولهذا فهو المصدر الذي يجب عليك تحقيق التزامن من أجله والتطبيقات الحقيقية يمكن أن تحوي العديد من كتل SyncLock والتي يمكن أن تستخدم نفس المتغير المحلي أو عدة متغيرات مختلفة من أجل اختلاف البصمة وهنا يجب عليك استخدام متغيرا مميزا من أجل كل نوع من أنواع المصادر المشتركة التي يجب عمل التزامن من اجلها أو من أجل مجموعة التعابير التي يجب تنفيذها ضمن المسار في نفس الوقت.
وعندما تستخدم كتلة SyncLock يتضمن الكود تلقائيا كتلة Try…End Try مخفية من أجل ضمان تحرير القفل بشكل صحيح إذا تم إطلاق استثناء ومن أجل هذا لا يمكنك القفز لعبارة داخل الكتلة SyncLock. وإن كانت الكتلة SyncLock موضوعة داخل إجراء خاص بتواجد Instance لفئة ما وجميع المسارات العاملة ضمن إجراء في ذلك التواجد Instance للفئة يمكنك تمرير Me لعبارة الـ SyncLock وذلك بسبب أن هذا الغرض يحقق كل المتطلبات (يمكن الوصول إليه من جميع المسارات – وهو قيمة مرجعية – وبالتأكيد هو ليس Nothing)
Class TestClass Sub TheTask() SyncLock Me ' Only one thread at a time can access this code. … End SyncLock End Sub End Class
ملاحظة: يمكنك استخدام Me بهذه الطريقة فقط إن كنت تريد عمل التزامن على مصدر وحيد كملف محدد مثلا أو نافذة الكونسول Console Window وإن كان لديك عدة كتل تزامن التي تحمي عدة مصادر ستستخدم بشكل تلقائي عدة متغيرات كبارامترات لكتلة SyncLock. والشئ الذي له أهمية أكبر مما ذكر هو أنه يجب عليك استخدام Me كبارامتر فقط إذا كانت الفئة غير مرئية خارج المجمع الحالي عدا ذلك يمكن لتطبيق آخر استخدام نفس التواجد Instance للفئة ضمن كتلة SyncLock مختلفة وبهذا فلن يتم تنفيذ عدة كتل من الكود بدون سبب حقيقي محدد وبشكل عام لا يجب عليك استخدام غرض Object عام مرئي من مجمعات أخرى كبارامتر لكتلة SyncLock. وتجدر الملاحظة أن العديد من الأكواد التي تراها على الانترنت تستخدم العامل GetType للحصول على نوع الغرض المستخدم للقفل lock object وذلك لحماية الطريقة الساكنة.
عندما تستخدم عبارات SyncLock معششة للقيام بالتزامن لأغراض مختلفة من الضروري استخدام تسلسل تعشيش متطابق أينما احتجت له في تطبيقك فالتحري عن الأقفال بالتسلسل المطابق ذاته يجنبك الوصول إلى حالة الأقفال الميتة خلال العديد من أجزاء التطبيق وهذه القاعدة تنطبق أيضا عندما تقوم دالة تحتوي على SyncLock باستدعاء دالة أخرى تحتوي على SyncLock
' Always use this sequence when locking objLock1 and objLock2. SyncLock objLock1 SyncLock objLock2 … End SyncLock End SyncLock