单生产者多个消费者实施

时间:2015-09-12 22:13:25

标签: c# multithreading

考虑以下情况

 private BlockingCollection<Consumer> consumers { get; set; }


 ThreadPool.QueueUserWorkItem((x) => {

                while (consumers.Count == 0)
                    Thread.Sleep(20);

                Consumer consumer;
                if (consumers.TryTake(out consumer)) {
                    var result = consumer.Read(data);
                    //do stuff with result
                    if (consumers.TryAdd(consumer)) {
                        //ok
                    }
                }
            });

当没有消费者可以处理请求时,有没有办法避免这种超时?

2 个答案:

答案 0 :(得分:5)

这可能是一个迟到的答案,但我会这样做(假设您的 Producer 生成一些字符串数据而消费者使用它们)

public class PC
{
    const int THREADS = 5;
    static BlockingCollection<string> _Collection = new BlockingCollection<string>();

    public PC()
    {
        //1 producer  
        Task.Run(()=>Producer());
        //N consumer
        for (int i = 0; i < THREADS; i++) Task.Run(() => Consumer());
    }

    void Producer()
    {
        Random rnd = new Random();
        while(true)
        {
            Thread.Sleep(100); //Not to flood our case...
             //Produce it
            _Collection.Add(rnd.Next().ToString());
        }
    }

    void Consumer()
    {
        while(true)
        {
            string str = _Collection.Take();
            //Consume it
            Console.WriteLine("Thread \"{0}\" consumed {1}", Thread.CurrentThread.ManagedThreadId, str);
        }
    }
}

答案 1 :(得分:2)

为您的消费者收藏集使用BlockingCollection。当没有可用的对象时,它将阻止Take()调用,并在项目可用时立即继续。

编辑(在OP显示它已经在使用BlockingCollection之后): 将TakeTake调用替换为Take阻止调用,直到某个项目可用为止。并一起删除Thread.Sleep调用。

编辑:添加了代码段。

Consumer consumer = consumers.Take();
var result = consumer.Read(data); //do stuff with result 
if (consumers.TryAdd(consumer)) 
{ 
   //ok 
}