2

I have a NetworkStream that I use to get data from another program. The data arrives as a Byte[64], which I then Enqueue to a ConcurrentQueue so that another thread can dequeue for analysis later. The queue is instantiated:

ConcurrentQueue<byte[]> fifo = new ConcurrentQueue<byte[]>();

then I Enqueue all the data being sent:

Byte[] bytesIn = new Byte[64];
int i;
while ((i = stream.Read(bytesIn, 0, bytesIn.Length)) != 0)
{
    fifo.Enqueue(bytesIn);
}

If I then look at (during debug) the data in fifo it turns out that every byte[64] contained therin is identical to the latest bytesIn. How do I ensure that the arrays I'm adding to fifo are the values and not the pointers (if that's the correct terminology)?

zotty
  • 797
  • 2
  • 9
  • 27

2 Answers2

7

Enqueue a copy of the array instead. You can use the ToArray extension for this.

while ((i = stream.Read(bytesIn, 0, bytesIn.Length)) != 0)
{
    var received = bytesIn.Take(i).ToArray();
    fifo.Enqueue(received);
}

I also used Take to trim the buffer, and copy only the bytes that were received.

Alternatively, as suggested by @hvd in the comments, using Array.Copy will be faster

while ((i = stream.Read(bytesIn, 0, bytesIn.Length)) != 0)
{
    var received = new byte[i];
    Array.Copy(bytesIn, 0, received, 0, i);

    fifo.Enqueue(received);
}
dcastro
  • 66,540
  • 21
  • 145
  • 155
  • 5
    In general I'd say not to bother with premature optimisations, but in this case I think it's clear enough that `Take(i).ToArray()` does a lot more work than needed, that it's likely to have a significant measurable impact, and it's easy enough to clearly write it in a way that avoids that problem: `var received = new byte[i];` followed by a call to `Array.Copy`. –  Sep 11 '15 at 10:40
  • That works a treat, thanks! is there a performance difference between `CopyTo` and `Buffer.BlockCopy` ? – zotty Sep 11 '15 at 10:48
  • 1
    @zotty no prob. this may help: [Array.Copy vs Buffer.BlockCopy](http://stackoverflow.com/questions/1389821/array-copy-vs-buffer-blockcopy) – dcastro Sep 11 '15 at 10:49
  • 1
    @zotty If you're working with so much data that this difference matters, you might not want to allocate new arrays all the time, but rather use an object pool. The GC is fast, but it has its limits. – CodesInChaos Sep 11 '15 at 11:08
2

I think the main issue here is your misunderstanding of adding a reference type to the queue which you have declared outside your while-loop.

If you take a close look at the code you provided, you can see you only declare bytesIn once. You enqueue the bytesIn, and then rewrite the value of the array. The array is, however, still the same object as before and can thus not be queued again, hence it changes the array to the new value.

So what's it what we actually want to do? We want to;

  • Read the stream
  • Put the output in a new array-object
  • Enqueue the new object

Which is exactly what @dcastro does, but I'll strip down the code for you;

while ((
         i = stream.Read(bytesIn, 0, bytesIn.Length)) != 0    //read the contents of the 
                                                              //stream and put it in 
                                                              //bytesIn, if available 
                                                            )
{
    var received = new byte[i];              //Create a new, empty array, which we are 
                                             //going to put in the queue.

    Array.Copy(bytesIn, 0, received, 0, i);  //Copy the contents of bytesIn into our new
                                             //array. This way we can reuse bytesIn while
                                             //maintaining the received data.

    fifo.Enqueue(received);                  //Enqueue the new array and thus saving it.
} 

For more information, perhaps you should read about Reference types.

Dion V.
  • 2,090
  • 2
  • 14
  • 24