03-10-12, 08:33 AM
كاتب الموضوع : samerselo
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
وعندما تستخدم كتلة 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
عندما تستخدم عبارات SyncLock معششة للقيام بالتزامن لأغراض مختلفة من الضروري استخدام تسلسل تعشيش متطابق أينما احتجت له في تطبيقك فالتحري عن الأقفال بالتسلسل المطابق ذاته يجنبك الوصول إلى حالة الأقفال الميتة خلال العديد من أجزاء التطبيق وهذه القاعدة تنطبق أيضا عندما تقوم دالة تحتوي على SyncLock باستدعاء دالة أخرى تحتوي على SyncLock
كود :
' Always use this sequence when locking objLock1 and objLock2.
SyncLock objLock1
SyncLock objLock2
…
End SyncLock
End SyncLock
تضمين جميع الأكواد التي تستخدم متغيرات مشتركة ضمن كتلة SyncLock يؤدي إلى إبطاء تطبيقك كثيرا أو تخفيض أداؤه بشكل ملحوظ وبشكل خاص عندما يتم تشغيله على حاسب متعدد المعالجات فإن استطعت تجنب استخدام كتلة SyncLock بدون تعريض تكامل البيانات للخطر يجب عليك القيام به قطعيا فمثلا تخيل أنك تستخدم نمط وحيد بتواجد كسول lazy instantiation في بيئة متعددة المسارات
كود :
Public Class Singleton
Private Shared m_Instance As Singleton
Private Shared sharedLock As New Object()
Public Shared ReadOnly Property Instance() As Singleton
Get
SyncLock sharedLock
If m_Instance Is Nothing Then m_Instance = New Singleton
Return m_Instance
End SyncLock
End Get
End Property
End Class
كود :
Class Singleton
Private Shared m_Instance As Singleton
Private Shared sharedLock As New Object
Public Shared ReadOnly Property Instance() As Singleton
Get
If m_Instance Is Nothing Then
SyncLock sharedLock
If m_Instance Is Nothing Then m_Instance = New Singleton()
End SyncLock
End If
Return m_Instance
End Get
End Property
End Class
مشكلة أخرى متعلقة بالمسارات في الدوت نيت هي أن ليس جميع أغراض الدوت نيت .NET object قابلة للمشاركة بأمان عبر المسارات not all .NET objects are thread-safeفعندما تقوم بكتابة تطبيق متعدد المسارات يجب عليك التأكد دوما من الوثائق للتأكد من أن الأغراض والطرائق التي تستخدمها آمنة للاستخدام عبر المسارات فعلى سبيل المثال جميع الطرق الساكنة للفئات Regex و Match أمنة عبر المسارات ولكن الطرق الغير ساكنة غير آمنة فيجب عدم استخدامها ضمن مسار مختلف وكذلك بعض أغراض الدوت نيت مثل Windows Forms objects and controls لها العديد من الحدود التي تجعل فقط المسار الذي أنشأها يمكنه استدعاء طرقها وخصائصها
أنواع دوت نيت المتزامنة Synchronized .NET Types
العديد من الأغراض الغير آمنة عبر المسارات بطبيعتها مثل ArrayList و Hashtable و Queue و SortedList و Stack و TextReader و TextWriter و التعابير النظامية تقدم طريقة ساكنة قابلة للتزامن تعيد غرض أمن للمسارات thread-safe object مكافئ للذي تم تمريره كما أن معظمها يعرض الخاصية IsSynchronized التي تعيد True عندما تتعامل مع نسخة آمنة عبر المسارات
كود :
' Create an ArrayList object, and add some values to it.
Dim al As New ArrayList()
al.Add(1): al.Add(2): al.Add(3)
' Create a synchronized, thread-safe version of this ArrayList.
Dim syncAl As ArrayList = ArrayList.Synchronized(al)
' Prove that the new object is thread-safe.
Console.WriteLine(al.IsSynchronized) ' => False
Console.WriteLine(syncAl.IsSynchronized) ' => True
' You can now share the syncAl object among different threads
The Synchronization Attribute
استخدام الخاصية System.Runtime.Remoting.Contexts.Synchronization هي أبسط طريقة لتحقيق الوصول المتزامن للغرض Object بأكمله وبذلك يستطيع مسار واحد فقط الوصول إلى حقوله وطرائقه وبذلك أي مسار يستطيع استخدام الفئة ولكن مسار واحد فقط يستطيع تنفيذ أحد طرائقه إذا كانت الطريقة تنفذ كودا ضمن الفئة Class وأي مسار يحاول استخدام هذه الفئة عليه الانتظار وبكلمات أخرى وكأن هناك كتل SyncLock تغلف كافة طرائق الفئة مستخدمة نفس متغير الإقفال. والكود التالي يبين كيف يمكنك مزامنة فئة باستخدام الخاصية Synchronization attribute لاحظ أيضا أن الفئة يجب أن يتم وراثتها من ContextBoundObject ليتم تعليمها كـ context-bound object
كود :
System.Runtime.Remoting.Contexts.Synchronization()> _
Class Display
Inherits ContextBoundObject
…
End Class