.NET Synchronised Dictionary
In .NET 2.0 and above the SyncRoot was removed from the Dictionary and
Hastable classes which meant you can't create thread-safe versions of
these anymore. This was done (properly in my reasoning) by the .NET
team to move synchronisation to be the responsibility of the developer
as synchronisation usually happens at a higher level and could involve
multiple resources which needed to be synchronised together.
Now saying all that, there are places where a simple thread safe dictionary or list class is just a necessity and it's a complete pain having to develop your our synchronisation around it each time.
So
here I provide a simple implementation of a generic synchronised
dictionary class that is thread-safe, this was developed in .NET 3.5
using the new Threading.ReaderWriterLockSlim class.
Public Class SynchronisedDictionary(Of KEY_TYPE, ITEM_TYPE)Original Author
Implements IDictionary(Of KEY_TYPE, ITEM_TYPE)
Private _rwLock As New Threading.ReaderWriterLockSlim
Private _dict As New Generic.Dictionary(Of KEY_TYPE, ITEM_TYPE)
Private Class AcquireWriteLock
Implements IDisposable
Private _rwLock As New Threading.ReaderWriterLockSlim
Public Sub New(ByVal rwLock As Threading.ReaderWriterLockSlim)
_rwLock = rwLock
_rwLock.EnterWriteLock()
End Sub
Private disposedValue As Boolean = False ' To detect redundant calls
' IDisposable
Protected Overridable Sub Dispose(ByVal disposing As Boolean)
If Not Me.disposedValue Then
If disposing Then
' TODO: free other state (managed objects).
_rwLock.ExitWriteLock()
End If
' TODO: free your own state (unmanaged objects).
' TODO: set large fields to null.
End If
Me.disposedValue = True
End Sub
#Region " IDisposable Support "
' This code added by Visual Basic to correctly implement the disposable pattern.
Public Sub Dispose() Implements IDisposable.Dispose
' Do not change this code. Put cleanup code in Dispose(ByVal disposing As Boolean) above.
Dispose(True)
GC.SuppressFinalize(Me)
End Sub
#End Region
End Class
Private Class AcquireReadLock
Implements IDisposable
Private _rwLock As New Threading.ReaderWriterLockSlim
Public Sub New(ByVal rwLock As Threading.ReaderWriterLockSlim)
_rwLock = rwLock
_rwLock.EnterReadLock()
End Sub
Private disposedValue As Boolean = False ' To detect redundant calls
' IDisposable
Protected Overridable Sub Dispose(ByVal disposing As Boolean)
If Not Me.disposedValue Then
If disposing Then
' TODO: free other state (managed objects).
_rwLock.ExitReadLock()
End If
' TODO: free your own state (unmanaged objects).
' TODO: set large fields to null.
End If
Me.disposedValue = True
End Sub
#Region " IDisposable Support "
' This code added by Visual Basic to correctly implement the disposable pattern.
Public Sub Dispose() Implements IDisposable.Dispose
' Do not change this code. Put cleanup code in Dispose(ByVal disposing As Boolean) above.
Dispose(True)
GC.SuppressFinalize(Me)
End Sub
#End Region
End Class
Public Sub Add(ByVal item As System.Collections.Generic.KeyValuePair(Of KEY_TYPE, ITEM_TYPE)) Implements System.Collections.Generic.ICollection(Of System.Collections.Generic.KeyValuePair(Of KEY_TYPE, ITEM_TYPE)).Add
Using New AcquireWriteLock(_rwLock)
_dict(item.Key) = item.Value
End Using
End Sub
Public Sub Clear() Implements System.Collections.Generic.ICollection(Of System.Collections.Generic.KeyValuePair(Of KEY_TYPE, ITEM_TYPE)).Clear
Using New AcquireWriteLock(_rwLock)
_dict.Clear()
End Using
End Sub
Public Function Contains(ByVal item As System.Collections.Generic.KeyValuePair(Of KEY_TYPE, ITEM_TYPE)) As Boolean Implements System.Collections.Generic.ICollection(Of System.Collections.Generic.KeyValuePair(Of KEY_TYPE, ITEM_TYPE)).Contains
Using New AcquireReadLock(_rwLock)
Return _dict.Contains(item)
End Using
End Function
Public Sub CopyTo(ByVal array() As System.Collections.Generic.KeyValuePair(Of KEY_TYPE, ITEM_TYPE), ByVal arrayIndex As Integer) Implements System.Collections.Generic.ICollection(Of System.Collections.Generic.KeyValuePair(Of KEY_TYPE, ITEM_TYPE)).CopyTo
Using New AcquireReadLock(_rwLock)
_dict.ToArray.CopyTo(array, arrayIndex)
End Using
End Sub
Public ReadOnly Property Count() As Integer Implements System.Collections.Generic.ICollection(Of System.Collections.Generic.KeyValuePair(Of KEY_TYPE, ITEM_TYPE)).Count
Get
Using New AcquireReadLock(_rwLock)
Return _dict.Count
End Using
End Get
End Property
Public ReadOnly Property IsReadOnly() As Boolean Implements System.Collections.Generic.ICollection(Of System.Collections.Generic.KeyValuePair(Of KEY_TYPE, ITEM_TYPE)).IsReadOnly
Get
Return False
End Get
End Property
Public Function Remove(ByVal item As System.Collections.Generic.KeyValuePair(Of KEY_TYPE, ITEM_TYPE)) As Boolean Implements System.Collections.Generic.ICollection(Of System.Collections.Generic.KeyValuePair(Of KEY_TYPE, ITEM_TYPE)).Remove
Using New AcquireWriteLock(_rwLock)
Return _dict.Remove(item.Key)
End Using
End Function
Public Sub Add(ByVal key As KEY_TYPE, ByVal value As ITEM_TYPE) Implements System.Collections.Generic.IDictionary(Of KEY_TYPE, ITEM_TYPE).Add
Using New AcquireWriteLock(_rwLock)
_dict(key) = value
End Using
End Sub
Public Function ContainsKey(ByVal key As KEY_TYPE) As Boolean Implements System.Collections.Generic.IDictionary(Of KEY_TYPE, ITEM_TYPE).ContainsKey
Using New AcquireReadLock(_rwLock)
Return _dict.ContainsKey(key)
End Using
End Function
Default Public Property Item(ByVal key As KEY_TYPE) As ITEM_TYPE Implements System.Collections.Generic.IDictionary(Of KEY_TYPE, ITEM_TYPE).Item
Get
Using New AcquireReadLock(_rwLock)
Return _dict(key)
End Using
End Get
Set(ByVal value As ITEM_TYPE)
Using New AcquireWriteLock(_rwLock)
_dict(key) = value
End Using
End Set
End Property
Public ReadOnly Property Keys() As System.Collections.Generic.ICollection(Of KEY_TYPE) Implements System.Collections.Generic.IDictionary(Of KEY_TYPE, ITEM_TYPE).Keys
Get
Using New AcquireReadLock(_rwLock)
Return _dict.Keys
End Using
End Get
End Property
Public Function Remove(ByVal key As KEY_TYPE) As Boolean Implements System.Collections.Generic.IDictionary(Of KEY_TYPE, ITEM_TYPE).Remove
Using New AcquireWriteLock(_rwLock)
_dict.Remove(key)
End Using
End Function
Public Function TryGetValue(ByVal key As KEY_TYPE, ByRef value As ITEM_TYPE) As Boolean Implements System.Collections.Generic.IDictionary(Of KEY_TYPE, ITEM_TYPE).TryGetValue
Using New AcquireReadLock(_rwLock)
Return _dict.TryGetValue(key, value)
End Using
End Function
Public ReadOnly Property Values() As System.Collections.Generic.ICollection(Of ITEM_TYPE) Implements System.Collections.Generic.IDictionary(Of KEY_TYPE, ITEM_TYPE).Values
Get
Using New AcquireReadLock(_rwLock)
Return _dict.Values
End Using
End Get
End Property
Public Function GetEnumeratorGeneric() As System.Collections.Generic.IEnumerator(Of System.Collections.Generic.KeyValuePair(Of KEY_TYPE, ITEM_TYPE)) Implements System.Collections.Generic.IEnumerable(Of System.Collections.Generic.KeyValuePair(Of KEY_TYPE, ITEM_TYPE)).GetEnumerator
Using New AcquireReadLock(_rwLock)
Return _dict.GetEnumerator
End Using
End Function
Public Function GetEnumerator() As System.Collections.IEnumerator Implements System.Collections.IEnumerable.GetEnumerator
Using New AcquireReadLock(_rwLock)
Return _dict.GetEnumerator
End Using
End Function
End Class
Original article written by Noel Lysaght
- Login or register to post comments
- 691 reads
- Email this Quick Tip
- Printer-friendly version
(Note: Opinions expressed in this article and its replies are the opinions of their respective authors and not those of DZone, Inc.)






