03-10-12, 08:35 AM
The Semaphore Type
تقدم الفريموورك 2 و فيجول بايزيك دوت نيت نوعا جديدا وهو Semaphore type الذي يرتكز على Win32 semaphore object وخلافا لبقية أغراض المسارات الموجودة في المكتبة mscorlib فهذا النوع تم تعريفه في المكتبة system.dll وهو يستخدم عندما تريد تحديد حد أقصى (عدد N) من المسارات التي يمكن تنفيذها في جزء معين من الكود أو للوصول إلى مصدر معين ويمتلك عددا ابتدائيا وعددا أقصى ويجب عليك تمرير هذه القيم لبانيه
كود :
' A semaphore that has an initial count of 1 and a maximum count of 2.
Dim sem As New Semaphore(1, 2)كود :
Dim sem As New Semaphore(2, 2)
' Next statement brings count from 2 to 1.
sem.WaitOne()
…
' Next statement brings count from 1 to 2.
sem.Release()
' Next statement attempts to bring count from 2 to 3, but
' throws a SemaphoreFullException.
sem.Release()
وبشكل أساسي ستستخدم الغرض Semaphore كما يلي
' Initial count is initially equal to max count.
Dim sem2 As New Semaphore(2, 2)
Sub Semaphore_Example()
' Wait until a resource becomes available.
sem2.WaitOne()
' Enter the synchronized section.
…
' Exit the synchronized section, and release the resource.
sem2.Release()
End Subكود :
Dim ownership As Boolean
Dim sem3 As New Semaphore(2, 2, "semaphoreName", ownership)
If ownership Then
' Current thread has the ownership of the semaphore.
…
End Ifكود :
' Wait until two mutexes, two semaphores, and one event object become signaled.
Dim waitHandles() As WaitHandle = {mutex1, mutex2, sem1, sem2, event1}
WaitHandle.WaitAll(waitHandles)العديد من المصادر في العالم الحقيقي يمكن إما القراءة منها أو الكتابة إليها وهي تدعم في الغالب إما مجموعة قراءات متعددة أو عملية كتابة وحيدة يتم تنفيذها في لحظة معينة فمثلا يمكن لعدة عملاء القراءة من ملف بيانات أو جدول في قاعدة بيانات ولكن إن تمت الكتابة للملف أو الجدول فلا يمكن حدوث أي عمليات قراءة أو كتابة على ذلك المصدر حيث يمكنك تعريف قفلا لكتابة واحدة أو عدة قراءات بدلالة الغرض ReaderWriterLock واستخدام هذا الغرض يعتبر رؤية إلى الأمام فكل المسارات التي تريد استخدام مصدر معين يجب عليها استخدام نفس الغرض ReaderWriterLock وقبل محاولة القيام بأي عملية على ذلك المصدر يجب على المسار استدعاء إما الطريقة AcquireReaderLock أو الطريقة AcquireWriterLock وذلك اعتمادا على العملية التي يتم تنفيذها وهذه الطرائق تقوم بإيقاف المسار الحالي حتى يتم الحصول على ذلك المصدر وأخيرا على المسار استدعاء الطريقة ReleaseReaderLock أو الطريقة ReleaseWriterLock عندما تنهي عملية القراءة أو الكتابة على ذلك المصدر والمثال التالي يقوم بإنشاء 10 مسارات تقوم بعملية قراءة أو كتابة على مصدر مشترك
كود :
Dim rwl As New ReaderWriterLock()
Dim rnd As New Random()
Sub TestReaderWriterLock()
For i As Integer = 0 To 9
Dim t As New Thread(AddressOf ReaderWriterLock_Task)
t.Start(i)
Next
…
End Sub
Sub ReaderWriterLock_Task(ByVal obj As Object)
Dim n As Integer = CInt(obj)
' Perform 10 read or write operations. (Reads are more frequent.)
For i As Integer = 1 To 10
If rnd.NextDouble < 0.8 Then
' Attempt a read operation.
rwl.AcquireReaderLock(Timeout.Infinite)
Console.WriteLine("Thread #{0} is reading", n)
Thread.Sleep(300)
Console.WriteLine("Thread #{0} completed the read operation", n)
rwl.ReleaseReaderLock()
Else
' Attempt a write operation.
rwl.AcquireWriterLock(Timeout.Infinite)
Console.WriteLine("Thread #{0} is writing", n)
Thread.Sleep(300)
Console.WriteLine("Thread #{0} completed the write operation", n)
rwl.ReleaseWriterLock()
End If
Next
End Subكود :
' Attempt to acquire a reader lock for no longer than 1 second.
rwl.AcquireWriterLock(1000)
If rwl.IsWriterLockHeld Then
' The thread has a writer lock on the resource.
…
End IfThe Interlocked Type
يزودنا النوع Interlocked بطريقة للقيام بعمليات دقيقة لزيادة أو إنقاص قيمة متغير مشترك وهذه الفئة تعرض فقط طرائق ساكنة (لا نحتسب هنا ما تمت وراثته من Object) انظر إلى الكود التالي
كود :
' Increment and Decrement methods work with 32-bit and 64-bit integers.
Dim lockCounter As Integer
…
' Increment the counter and execute some code if its previous value was zero.
If Interlocked.Increment(lockCounter) = 1 Then
…
End If
' Decrement the shared counter.
Interlocked.Decrement(lockCounter)كود :
If Interlocked.Add(lockCounter, 2) <= 10 Then …كود :
Dim s1 As String = "123"
Dim s2 As String = Interlocked.Exchange(s1, "abc")
Console.WriteLine("s1={0}, s2={1}", s1, s2)The ManualResetEvent, AutoResetEvent, and EventWaitHandle Types
هذه الفئات الثلاثة تعمل بشكل متشابه ManualResetEvent و AutoResetEvent و EventWaitHandle والفئة الأخيرة هي الفئة الأب للفئتان الأولان وقد تمت إضافتها في الفريموورك 2 على الرغم من أن ManualResetEvent و AutoResetEvent لم يتم إهمالهما بعد وأثناء العمل يمكنك استبدالهما بالفئة الجديدة EventWaitHandle التي تعطيك مزيدا من المرونة عند التعامل. والنوعان ManualResetEvent و AutoResetEventمفيدان بشكل خاص عندما تريد إيقاف مسار أو أكثر بشكل مؤقت حتى يخبرنا مسار آخر بأنه لا مانع من المتابعة وتستخدمهما لإيقاظ مسار مثل إجراء معالجة الحدث في مسار متوقف ولكن لا تنخدع بوجود Event في أسمائهما فلا يمكنك استخدام إجراءات معالجة الحدث التقليدية مع هذه الأغراض. وكائن من أحد هذين النوعين يمكن أن يكون في حالة إشارة أو عدم إشارة Signale/UnSignaled وهذه القيمة لا تملك أي معنى خاص بحيث يمكنك اعتبارها كحالة تشغيل/إيقاف حيث ستمرر الحالة الابتدائية للباني وأي مسار يستطيع الوصول لذلك الغرض يمكنه ضبط تلك الحالة إلى Signaled باستخدام الطريقة Set أو يستخدم الطريقة Reset لإعادة الحالة إلى UnSignaled ويمكن للمسارات الأخرى استخدام الطريقة WaitOne للانتظار حتى تصبح في حالة إشارة Signaled أو حتى انتهاء فترة الانتظار
كود :
' Create an auto reset event object in nonsignaled state.
Dim are As New AutoResetEvent(False)
' Create a manual reset event object in signaled state.
Dim mre As New ManualResetEvent(True)كود :
' These statements are equivalent to the previous code example.
Dim are As New EventWaitHandle(False, EventResetMode.AutoReset)
Dim mre As New EventWaitHandle(True, EventResetMode.ManualReset)ويبين المثال التالي كيف يمكن أن يكون لديك عدة مسارات منتجة تقوم بعملية البحث عن ملف في عدة مجلدات مختلفة في نفس الوقت ولكن يوجد مسار مستهلك وحيد يقوم بجمع النتائج من تلك المسارات ويستخدم المثال الغرض AutoResetEvent لإيقاظ المسار المستهلك عندما يتم إضافة اسم ملف جديد للقائمة List(Of String) ويستخدم أيضا الفئة Interlocked لإدارة عدد المسارات العاملة حتى يعلم المسار الرئيسي أنه لم تعد توجد أي بيانات أخرى لاستهلاكها
كود :
' The shared AutoResetEvent object
Public are As New AutoResetEvent(False)
' The list where matching filenames should be added
Public fileList As New List(Of String)()
' The number of running threads
Public searchingThreads As Integer
' An object used for locking purposes
Public lockObj As New Object()
Sub TestAutoResetEvent()
' Search *.zip files in all the subdirectories of C.
For Each dirname As String In Directory.GetDirectories("C:\")
Interlocked.Increment(searchingThreads)
' Create a new wrapper class, pointing to a subdirectory.
Dim sf As New FileFinder()
sf.StartPath = dirname
sf.SearchPattern = "*.zip"
' Create and run a new thread for that subdirectory only.
Dim t As New Thread(AddressOf sf.StartSearch)
t.Start()
Next
' Remember how many results we have so far.
Dim resCount As Integer = 0
Do While searchingThreads > 0
' Wait until there are new results.
are.WaitOne()
SyncLock lockObj
' Display all new results.
For i As Integer = resCount To fileList.Count - 1
Console.WriteLine(fileList(i))
Next
' Remember that you've displayed these filenames.
resCount = fileList.Count
End SyncLock
Loop
Console.WriteLine("")
Console.WriteLine("Found {0} files", resCount)
End Subكود :
Class FileFinder
Public StartPath As String ' The starting search path
Public SearchPattern As String ' The search pattern
Sub StartSearch()
Search(Me.StartPath)
' Decrease the number of running threads before exiting.
Interlocked.Decrement(searchingThreads)
' Let the consumer know it should check the thread counter.
are.Set()
End Sub
' This recursive procedure does the actual job.
Sub Search(ByVal path As String)
' Get all the files that match the search pattern.
Dim files() As String = Directory.GetFiles(path, SearchPattern)
' If there is at least one file, let the main thread know about it.
If files IsNot Nothing AndAlso files.Length > 0 Then
' Ensure found files are added as an atomic operation.
SyncLock lockObj
' Add all found files.
fileList.AddRange(files)
' Let the consumer thread know about the new filenames.
are.Set()
End SyncLock
End If
' Repeat the search on all subdirectories.
For Each dirname As String In Directory.GetDirectories(path)
Search(dirname)
Next
End Sub
End Classكود :
Create a system-wide auto reset event that is initially in the signaled state.
Dim ownership As Boolean
Dim ewh As New EventWaitHandle(True, EventResetMode.AutoReset, "eventname", ownership)
If ownership Then
' The event object was created by the current thread.
…
End Ifكود :
' This statement throws a WaitHandleCannotBeOpenedException if the specified
' event doesn't exist, or an UnauthorizedAccessException if the current
' user doesn't have the required permissions.
ewh = EventWaitHandle.OpenExisting("eventname", EventWaitHandleRights.FullControl)