Hey guys,
We are recieving data from socket, and displaying it on a listbox. Idea was to limit the number of oncollectionchanges, to prevent dispatcher hangs. So we switched to "ObservableCollectionExtended", incoming data is very fast about 3000 messages per second, hence we tried to simulate this (in the attached sample with multiple producers on timers)
We are using following simple logic to update the observable collection periodically using insertrange, and removerange (to limit the number of records in the observable collection to 2 million. After about 5 mins of run, ObservableCollectionExtended throws an unhandled exception: Destination array is not long enough to coy all the items in the collection. Check array index and length (sample code is attached).
lock (_locSync)
{
try
if (_orderList.Count > 0)
OrderCollection.BeginUpdate();
OrderCollection.InsertRange(0, _orderList);
Int32 count = OrderCollection.Count;
Int32 excess = count - _maxLimit;
if (count > _maxLimit)
OrderCollection.RemoveRange((_maxLimit - 1), excess);
OrderCollection.EndUpdate();
_orderList.Clear();
}
catch (Exception ee) { String s = String.Empty; }
Could you help please? Code is running on .Net framework 4.5.2.
FastData - Copy.zip
Regards,
Vinay
Hello,
I believe the issue here would be overlapping timer calls on a locked thread. I see 9 timers with an interval of 1 millisecond. Since EnableCollectionSynchronization has been enabled, and you lock the thread when an operation starts, the rest of the timers will wait in queue. This queue will grow every time the thread is locked and a callback failed to acquire it, until you reach a point the application crashes.
A possible solution would be to reduce the number of timers, and to implement further synchronization logic that will jump out from calls that failed to acquire the lock, by using Monitor.TryEnter(_locsync, isLocked).
Finally, you could also stop the timer from generating calls by setting it to Timeout.Infinite for the duration of the lock.
Sincerely,Tihomir TonevAssociate Software Developer
This was just done to simulate fast data, since Timers won't go beyond 1 tick per milli second (I just created this sample POC to replicate the issue). In real environment - data is coming from exchange, on one single thread- and we are getting the same issue. Also notice, there are 2 different objects for locking.
I am able to replicate this issue with just one single timer as well (application crashed after 24K records on UI). Also, please note produce/consume are syncronized using _locSync object, for Observable collection syncronization, I have used a different object _syncLock.
Thank you for pointing this.
BindingOperations.EnableCollectionSynchronization(OrderCollection, _syncLock);
The first line enables synchronization using object _syncLock, while the thread is being locked by object _lockSync. This means there is no thread synchronization enabled at all, causing the exception.
In order to have the synchronization running, you need to be passing the same object from the lock. So change it to this:
BindingOperations.EnableCollectionSynchronization(OrderCollection, _locSync);
I've attached the modified sample(also modified locking the thread with Monitor.TryEnter in order to ensure no callback queue can accumulate). I had this sample run for 25 minutes with no exceptions, accumulating over 500k records, so I believe it should resolve all issues.
Sincerely,Tihomir TonevInfragistics
FastDataModified.zip