Platinum Partner
dotnet,.net,how-to,synchronisation,dictionary class

.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)
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 Author

Original article written by Noel Lysaght

{{ tag }}, {{tag}},

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}
{{ parent.authors[0].realName || parent.author}}

{{ parent.authors[0].tagline || parent.tagline }}

{{ parent.views }} ViewsClicks
Tweet

{{parent.nComments}}