How to properly syncronize a SortedList?

G

gregory_may

I keep getting an error:
Collection was modified; enumeration operation may not execute.

Error from the following code. I cant seem to get it to properly syncronize
the Clients object (Its a sorted list). Any suggestions:

Private Sub SendToClients(ByVal strMessage As String, ByVal sender As
UserConnection)

Dim client As UserConnection

Dim entry As DictionaryEntry

Dim SyncClients As SortedList

Try

'Need to lock the collection. Threads can be modifying the clients
collection

'While we are broadcasting. Very bad things can happen.

'Synclock .SyncRoot locks the collection for us.

SyncLock clients.SyncRoot

SyncClients = CType(clients.SyncRoot, SortedList)

For Each entry In SyncClients

'Make sure we have someone to send the message too.

If Not IsNothing(entry.Value) Then

client = CType(entry.Value, UserConnection)

' Exclude the sender.

If client.NetworkName <> sender.NetworkName Then

GracefulSendMessage(strMessage, client)

End If

End If

Next

End SyncLock

Catch ex As Exception

UpdateStatus("-------------------------")

UpdateStatus("ServerComm - SendToClients - Error: " & ex.Message)

UpdateStatus("Message: " & strMessage)

UpdateStatus("To: " & sender.NetworkName)

UpdateStatus("-------------------------")

End Try

End Sub
 
P

Peter Huang

Hi Gregory,


It seems that you wants to make a thread-safe sortedlist, and from the
error message, when you are enumerating the sortedlist in the thread,
another thread was changing the sortedlist.
If I have misunderstood, please feel free to let me know.

From the MSDN,
Thread Safety
Public static (Shared in Visual Basic) members of this type are safe for
multithreaded operations. Instance members are not guaranteed to be
thread-safe.

A SortedList can support multiple readers concurrently, as long as the
collection is not modified. To guarantee the thread safety of the
SortedList, all operations must be done through the wrapper returned by the
Synchronized method.

Enumerating through a collection is intrinsically not a thread-safe
procedure. Even when a collection is synchronized, other threads could
still modify the collection, which causes the enumerator to throw an
exception. To guarantee thread safety during enumeration, you can either
lock the collection during the entire enumeration or catch the exceptions
resulting from changes made by other threads.

http://msdn.microsoft.com/library/default.asp?url=/library/en-us/cpref/html/
frlrfsystemcollectionssortedlistclasstopic.asp

Here is the sample you may take a look.
Imports System
Imports System.Collections
Imports Microsoft.VisualBasic
Imports System.Threading.Thread
Public Class SamplesSortedList
Public Shared mySL As SortedList
Public Shared Sub ThreadProc()
SyncLock mySL.SyncRoot
Dim mySyncdSL As SortedList = mySL.Synchronized(mySL)
mySyncdSL.Add(7, "Seven")
For Each o As DictionaryEntry In mySyncdSL
Sleep(100)
Console.WriteLine(CurrentThread.Name + ": " +
o.Value.ToString())
Next
End SyncLock
End Sub

Public Shared Sub Main()
mySL = New SortedList
mySL.Add(2, "two")
mySL.Add(3, "three")
mySL.Add(1, "one")
mySL.Add(0, "zero")
mySL.Add(4, "four")
Dim th As New Threading.Thread(AddressOf ThreadProc)
th.Name = "SubThread"
th.Start()
SyncLock mySL.SyncRoot
mySL.Add(6, "Six")
Dim mySyncdSL As SortedList = mySL.Synchronized(mySL)
For Each o As DictionaryEntry In mySyncdSL
Threading.Thread.Sleep(100)
Console.WriteLine(o.Value)
Next
End SyncLock
th.Join()
Console.ReadLine()
End Sub
End Class

[NOTE: SyncLock mySL.SyncRoot will not lock the mySL, i.e. you can still
use the in mySL to add or remove item from other thread, please check if
you have any modification in other thread.]

If you change your code as below, the exception will occur.
Public Shared Sub ThreadProc()
'SyncLock mySL.SyncRoot
Dim mySyncdSL As SortedList = CType(mySL.SyncRoot, SortedList)
'.Synchronized(mySL)
mySyncdSL.Add(7, "Seven")
For Each o As DictionaryEntry In mySyncdSL
Sleep(100)
Console.WriteLine(CurrentThread.Name + ": " +
o.Value.ToString())
Next
'End SyncLock
End Sub

Please apply my suggestion above and let me know if it helps resolve your
problem.


Best regards,

Peter Huang
Microsoft Online Partner Support

Get Secure! - www.microsoft.com/security
This posting is provided "AS IS" with no warranties, and confers no rights.
 
G

gregory_may

You got it.

The list is being changed while I am reading it. I must be missing the
thread safe wrapper on the part of code that is changing the list?

g.

"Peter Huang" said:
Hi Gregory,


It seems that you wants to make a thread-safe sortedlist, and from the
error message, when you are enumerating the sortedlist in the thread,
another thread was changing the sortedlist.
If I have misunderstood, please feel free to let me know.

From the MSDN,
Thread Safety
Public static (Shared in Visual Basic) members of this type are safe for
multithreaded operations. Instance members are not guaranteed to be
thread-safe.

A SortedList can support multiple readers concurrently, as long as the
collection is not modified. To guarantee the thread safety of the
SortedList, all operations must be done through the wrapper returned by the
Synchronized method.

Enumerating through a collection is intrinsically not a thread-safe
procedure. Even when a collection is synchronized, other threads could
still modify the collection, which causes the enumerator to throw an
exception. To guarantee thread safety during enumeration, you can either
lock the collection during the entire enumeration or catch the exceptions
resulting from changes made by other threads.

http://msdn.microsoft.com/library/default.asp?url=/library/en-us/cpref/html/
frlrfsystemcollectionssortedlistclasstopic.asp

Here is the sample you may take a look.
Imports System
Imports System.Collections
Imports Microsoft.VisualBasic
Imports System.Threading.Thread
Public Class SamplesSortedList
Public Shared mySL As SortedList
Public Shared Sub ThreadProc()
SyncLock mySL.SyncRoot
Dim mySyncdSL As SortedList = mySL.Synchronized(mySL)
mySyncdSL.Add(7, "Seven")
For Each o As DictionaryEntry In mySyncdSL
Sleep(100)
Console.WriteLine(CurrentThread.Name + ": " +
o.Value.ToString())
Next
End SyncLock
End Sub

Public Shared Sub Main()
mySL = New SortedList
mySL.Add(2, "two")
mySL.Add(3, "three")
mySL.Add(1, "one")
mySL.Add(0, "zero")
mySL.Add(4, "four")
Dim th As New Threading.Thread(AddressOf ThreadProc)
th.Name = "SubThread"
th.Start()
SyncLock mySL.SyncRoot
mySL.Add(6, "Six")
Dim mySyncdSL As SortedList = mySL.Synchronized(mySL)
For Each o As DictionaryEntry In mySyncdSL
Threading.Thread.Sleep(100)
Console.WriteLine(o.Value)
Next
End SyncLock
th.Join()
Console.ReadLine()
End Sub
End Class

[NOTE: SyncLock mySL.SyncRoot will not lock the mySL, i.e. you can still
use the in mySL to add or remove item from other thread, please check if
you have any modification in other thread.]

If you change your code as below, the exception will occur.
Public Shared Sub ThreadProc()
'SyncLock mySL.SyncRoot
Dim mySyncdSL As SortedList = CType(mySL.SyncRoot, SortedList)
'.Synchronized(mySL)
mySyncdSL.Add(7, "Seven")
For Each o As DictionaryEntry In mySyncdSL
Sleep(100)
Console.WriteLine(CurrentThread.Name + ": " +
o.Value.ToString())
Next
'End SyncLock
End Sub

Please apply my suggestion above and let me know if it helps resolve your
problem.


Best regards,

Peter Huang
Microsoft Online Partner Support

Get Secure! - www.microsoft.com/security
This posting is provided "AS IS" with no warranties, and confers no rights.
 
P

Peter Huang

Hi Gergory,

Yes, as the MSDN said, we should use the Synchronized wrap to do operation
on the sortedlist. Because even if we have call the SyncLock mySL.SyncRoot
to lock the mySL.SyncRoot, we can still access the mySL directly.

Best regards,

Peter Huang
Microsoft Online Partner Support

Get Secure! - www.microsoft.com/security
This posting is provided "AS IS" with no warranties, and confers no rights.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top