I have the following method within my TcpServer
private void Receive(ZClient client)
{
NetworkStream ns = client.TcpClient.GetStream();
int bytesRead = 0;
byte[] message = new byte[client.TcpClient.ReceiveBufferSize];
while (true)
{
bytesRead = ns.Read(message, 0, client.TcpClient.ReceiveBufferSize);
if (bytesRead == 0)
{
break; // Exit Thread
}
else
{
Array.Resize<Byte>(ref client.Buffer, client.Buffer.Length + bytesRead);
Buffer.BlockCopy(message, 0, client.Buffer, client.Buffer.Length - bytesRead, bytesRead);
// Issue Below
DisassembleRawMessage(client); // *1 See below
new Thread(()=>DeQueueMessages(client)).Start(); // *2 See below
// End Issue
}
}
}
-
DissassembleRawMessage is responsible for handling the processing of my buffer and enquing individual messages in my client message queue. No problem here.
-
DeQueueMessages is responsible for processing the objects previously placed into my client message queue within the DissassembleRawMessage method.
The problem may seem pretty obvious. I spin off a new thread after the message is recieved. During the process of dequing and processing the individual messages, the queue may have more items added to it, as more data may have been recieved in the interm. This results in an enumeration error, prompting me that I may not modify the contents of the collection during the enumeration.
I don’t want to block my recieve method by processing the queue within the same thread, as it would defeat the purpose allowing the queue to build up requests, while still recieving data. How can I continue to queue objects, and at the same time, process the objects within the queue without running into enumeration modification exceptions?
Update: The method that dequeues the messages.
while (client.Queue.Count() > 0)
{
byte[] buffer = client.Queue.Dequeue();
...
}
First, I wouldn’t use a new thread for each message received. Either start a thread that waits for new work rather than exiting, or use the ThreadPool.
If you’re getting an InvalidOperationException during enumeration, that means you’re iterating over a list or other IEnumerable. Does that mean that you’re doing something like this?
If so, switch to using the actual Queue class, and do this while loop:
If memory serves, the standard System.Collections.Generic.Queue class isn’t thread safe, so I’d go with System.Collections.Concurrent.ConcurrentQueue.