为什么我的ConcurentSet不起作用?

时间:2011-05-01 11:04:48

标签: c#

我在这里要求任何ConcurentSet / ConcurentQueue实现how to create no-duplicates ConcurrentQueue?,但没有人提出任何建议。

所以我决定自己写一下,稍微修改一下MSDN的例子。 我创建了ConcurentSet课程。我插入两次相同的元素,并期望它只插入一次,因为Set在内部使用:

                numbers.Add(i);
                Console.WriteLine("Add:{0} Count={1}", i, numbers.Count);
                numbers.Add(i);
                Console.WriteLine("Add:{0} Count={1}", i, numbers.Count);

但是根据插入两次的输出元素:

    Add:0 Count=0
    Add:0 Count=1
    Add:1 Count=2
    Add:1 Count=3
    Add:2 Count=4
    Take:0
    Add:2 Count=5
    Add:3 Count=6
    Add:3 Count=7
    Add:4 Count=7
    Add:4 Count=8
    Take:3
    Add:5 Count=9
    Add:5 Count=10
    Add:6 Count=11
    Add:6 Count=12

问题是 - 为什么我的ConcurentSet实现不能按预期工作? 我期待这样的输出:

    Add:0 Count=0
    Add:0 Count=0
    Add:1 Count=1
    Add:1 Count=1
    Add:2 Count=2
    Take:0
    Add:2 Count=1
    Add:3 Count=2
    Add:3 Count=2
    Add:4 Count=3
    Add:4 Count=3
    Take:3
    Add:5 Count=3
    Add:5 Count=3
    .....

完整列表如下:

using System.Collections;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;

namespace BCBlockingAccess
{
using System;
using System.Collections.Concurrent;

public class ConcurentSet
: IProducerConsumerCollection<int>
{
    private readonly object m_lockObject = new object();
    private readonly HashSet<int> m_set = new HashSet<int>();

    public void CopyTo(Array array, int index)
    {
        throw new NotImplementedException();
    }

    public int Count { get { return m_set.Count; } }

    public object SyncRoot { get { return m_lockObject; } }

    public bool IsSynchronized { get { return true; } }

    public void CopyTo(int[] array, int index)
    {
        throw new NotImplementedException();
    }

    public bool TryAdd(int item)
    {
        lock (m_lockObject)
        {
            m_set.Add(item);
        }

        return true;
    }

    public bool TryTake(out int item)
    {
        lock (m_lockObject)
        {
            foreach (var i in m_set)
            {
                if (m_set.Remove(i))
                {
                    item = i;
                    return true;
                }
            }
            item = -1;
            return false;
        }
    }

    public int[] ToArray()
    {
        throw new NotImplementedException();
    }

    public IEnumerator<int> GetEnumerator()
    {
        throw new NotImplementedException();
    }

    IEnumerator IEnumerable.GetEnumerator()
    {
        return GetEnumerator();
    }
}


class Program
{
    static void Main(string[] args)
    {
        // Increase or decrease this value as desired.
        int itemsToAdd = 50;

        // Preserve all the display output for Adds and Takes
        Console.SetBufferSize(80, (itemsToAdd * 5) + 3);

        // A bounded collection. Increase, decrease, or remove the 
        // maximum capacity argument to see how it impacts behavior.
        BlockingCollection<int> numbers = new BlockingCollection<int>(new ConcurentSet());


        // A simple blocking consumer with no cancellation.
        Task.Factory.StartNew(() =>
        {
            int i = -1;
            while (!numbers.IsCompleted)
            {
                try
                {
                    i = numbers.Take();
                }
                catch (InvalidOperationException)
                {
                    Console.WriteLine("Adding was compeleted!");
                    break;
                }
                Console.WriteLine("Take:{0} ", i);

                // Simulate a slow consumer. This will cause
                // collection to fill up fast and thus Adds wil block.
                Thread.SpinWait(100000);
            }

            Console.WriteLine("\r\nNo more items to take. Press the Enter key to exit.");
        });

        // A simple blocking producer with no cancellation.
        Task.Factory.StartNew(() =>
        {
            for (int i = 0; i < itemsToAdd; i++)
            {
                numbers.Add(i);
                Console.WriteLine("Add:{0} Count={1}", i, numbers.Count);
                numbers.Add(i);
                Console.WriteLine("Add:{0} Count={1}", i, numbers.Count);
            }

            // See documentation for this method.
            numbers.CompleteAdding();
        });

        // Keep the console display open in debug mode.

        Console.ReadLine();
    }
}
}

1 个答案:

答案 0 :(得分:3)

BlockingCollection维护自己的计数并且不使用你的基础ConcurrentSet的计数,因此即使重复项被忽略,计数也会增加。

您可能希望在此集合周围编写自己的包装器,它从concurrentset返回计数并将每个其他方法属性中继到阻塞集合。