3

I want two threads on the same machine, one that populates a collection and the other one that pops data out of it as soon as it's available and stops when it know it's over. I just don't know what collection to use...

private void DataProviderThread()
{
    GlobalCollection = new SomeMagicCollection();

    for (int i = 0; i < 100; i++)
    {
        GlobalCollection.Add(new SomeDataItem(i));
        Thread.Sleep(100);
    }

    GlobalCollection.IHaveFinishedPopulatingThanksAndBye();
}

private void DataCruncherThread()
{
    foreach (var item in GlobalCollection)
    {
        // Do whatever
    }
    // The control should exit foreach only once the data provider states that the collection is finished  
}

I then want to iterate simply on it, having the Collection take care of

  • Staying thread safe
  • Grant the standard IEnumerable functionalities
  • Let my data cruncher thread wait for new items until the DataBuilder has explicitely called IHaveFinishedPopulatingThanksAndBye(), then cleanly exit the loop
  • Allow me to have several other threads iterating with the same constraints

I can't believe C# doesn't ship this in a new version. But what's its name?

PPC
  • 1,734
  • 1
  • 21
  • 41
  • possible duplicate of [awaitable Task based queue](http://stackoverflow.com/questions/7863573/awaitable-task-based-queue) – miniBill Feb 17 '15 at 17:09
  • ConcurrentQueue: https://msdn.microsoft.com/en-us/library/dd267265%28v=vs.110%29.aspx – DrKoch Feb 17 '15 at 17:10

1 Answers1

8

What you have is a classic Producer/Consumer pattern.

You can use a ConcurrentQueue<T> or, probably better, a BlockingCollection<T>

The BoundedCapacity property lets you regulate (throttle) the dataflow.

It is an IEnumerable<T> but don't try to use it like non-shared collection. The TryTake() method is the most useful way to get your data.

H H
  • 263,252
  • 30
  • 330
  • 514
  • Using it as an `IEnumerable` is a perfectly fine way to access the data, or if the situation warrants it, `GetConsumingEnumerable`. I find that I very rarely ever need to use `Take` or TryTake`, given those two options, both of which are designed to be used while the collection is modified from other threads. – Servy Feb 17 '15 at 17:34
  • For some kinds of operations using the IEnumerable interface is OK, as long as you're aware of the concurrency. I don't find the ConsumingEnumerable very clear to use but that's a matter of taste. – H H Feb 17 '15 at 18:02
  • You not thinking that it's clear is very different than it not working. Both operations are very much designed to be used in a multithreaded context. – Servy Feb 17 '15 at 18:08