2015-09-12 3 views
-2

Рассмотрим следующую ситуациюодного производителя реализация множественного потребителя

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 
        } 
       } 
      }); 

Есть ли способ избежать этого тайм-аут, когда не потребитель доступен для обработки запроса?

+0

Если вы используете 'тему «Спящий», ты делаешь что-то не так. Почему вы не используете 'WaitHandle' для блокировки потока? – Dai

+1

Вы пробовали 'System.Collections.Concurrent.BlockingCollection' для ex. Он имеет ограниченную емкость. – Eser

+0

Какой тип «потребителей»? Вам нужно изучить [семафор] (https://msdn.microsoft.com/en-us/library/system.threading.semaphore%28v=vs.110%29.aspx), чтобы позволить потребителю принимать X-элементы max, а затем ждать события, когда больше нет предметов –

ответ

2

Используйте коллекцию BlockingCollection для своих потребителей. Он будет блокироваться при вызове Take(), когда объекты недоступны и не будут продолжены, как только будут доступны предметы.

EDIT (после того, как OP показало, что уже использует BlockingCollection): Замените вызов TryTake вызовом Take, который блокируется до тех пор, пока элемент не будет доступен. И удалите вызов Thread.Sleep вместе.

EDIT: Добавлен фрагмент кода.

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

И в чем смысл сказать «использовать это», когда OP уже использует его – Eser

+0

@Eser Я не заметил декларацию коллекции потребителей. Возможно, добавлено в более позднее редактирование? –

+0

Но до вашего ответа ... – Eser

5

Это может быть поздний ответ, но я хотел бы сделать это таким образом (предположим, что ваш Производитель производит некоторые строковые данные и Потребители использовать их)

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); 
     } 
    } 
} 
+0

Это правильный образец производителя - потребителя. –

+0

отличный ответ, используя цикл while (true) у потребителя, не работают ли потоки?Может ли это вызвать какие-либо проблемы? Должен ли я управлять своим государством? – Hristo

+0

@Chris Цикл не будет жестким, потому что Take() будет блокироваться, когда элементы не будут доступны. –

Смежные вопросы