Home > Computers and Internet > An IProducerConsumer that does not work with the BlockingCollection

An IProducerConsumer that does not work with the BlockingCollection

Providing progress updates is a problem that many
applications have to deal with. As users, we like seeing that the computer is
working on our behalf and isn’t stuck. Something which adds a layer of
complexity to the providing updates problem is that a background thread is
normally the thread doing work, and the GUI thread is the thread that paints
the message/status for the user to see. So the hand shaking between the worker
thread and GUI thread is something which needs to be managed. It has been the
experience of some programmers that they are able to provide progress messages
so fast that it starts to slow down the GUI, and the background threads are
getting bottlenecked by providing progress updates.

In an attempt to solve this problem generically I wrote a
class which implements the IProducerConsumer interface, but will only ever
contain the latest item added to it. The idea being that background threads can
add progress updates to it at whatever rate they desire, but when the GUI
thread asks for progress, it will only get the latest progress message.

Curious to know if this IProducerConsumer implementation
worked as the underlying data store for the BlockingCollection class, I wrote a
test to see. The test case fails when the consumer thread calls
BlockingCollection.Take(), when three items have been added to the blocking
collection, but only two items have been taken from it. When writing the test
case I was expecting the BlockingCollection to block the thread on the call to
Take() because the underlying data store didn’t have any items in it. The last
item which had been added had already been taken. What happened when running
the test was an InvalidOperationException: The underlying collection was
modified from outside of the BlockingCollection.

At first I found this to be confusing, because the
underlying collection wasn’t modified from outside of BlockingCollection. All
of the calls to add or take items were made through the BlockingCollection. It
turns out that BlockingCollection keeps a count of how many times Add() has
been called and how many times Take() has been called. Since my
IProducerConsumer doesn’t behave similarly the BlockingCollection can’t behave
deterministically. This isn’t spelled out in the BlockingCollection documentation,
but is probably what “The BlockingCollection<T>
can become corrupted if the underlying collection is changed directly.”
is referring to. It is very important for a class like BlockingCollection to
behave deterministically, making it not unreasonable to enforce this behavior.

I was able to verify that BlockingCollection
tracks the number of items it expects the underlying data store to have by
adding a bunch of items to the BlockingCollection and then checking its Count
property. If the BlockingCollection was using the Count of the underlying
IProducerConsumer it would return a value of one, but if it kept its own count
it would return the number of times Add() had been called. The
BlockingCollection returned the number of times Add() had been called.

  1. No comments yet.
  1. No trackbacks yet.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: