2013-09-09 2 views
1

В моем приложении я использую разные потоки (по одному для каждой активной передачи). Я бы хотел, например, ограничить активные трансферы, поставив остальных приходящих в очередь.Thread syncronization in C#

На данный момент мое решение проверяет, есть ли место для другой активной передачи, если бы я не поместил запрос в список очередей. Каждый раз, когда у меня завершено событие, я выбираю один из очереди. (но я думаю, что мое решение действительно грязно)

Есть ли хороший способ запланировать активные потоки?

Использует семафор хороший (и аккуратный) выбор?

+0

Проверьте 'System.Threading.ThreadPool', особенно' ThreadPool.QueueUserWorkItem'. – jlahd

+0

Вероятно, вы должны показать какой-то код, показать, что вы попробовали, и рассказать, что не работает с этим решением, и что вы хотите сделать –

+0

Какой тип «передачи» это? (файл, сеть?), как правило, нецелесообразно выделять потоки для интенсивных операций ввода-вывода. –

ответ

3

Вы можете использовать BlockingCollection для управления очередью, например:

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

namespace Demo 
{ 
    public class Program 
    { 
     private readonly BlockingCollection<int> _queue = new BlockingCollection<int>(); 

     private void run() 
     { 
      const int CONSUMER_COUNT = 8; 

      Task[] tasks = new Task[CONSUMER_COUNT]; 

      for (int i = 0; i < CONSUMER_COUNT; ++i) 
      { 
       int id = i; 
       tasks[i] = Task.Run(() => process(id)); 
      } 

      Console.WriteLine("Press <return> to start adding to the queue."); 
      Console.ReadLine(); 

      for (int i = 0; i < 100; ++i) 
      { 
       Console.WriteLine("Adding item #{0}", i); 
       _queue.Add(i); 
      } 

      Console.WriteLine("Press <return> to close the queue."); 
      Console.ReadLine(); 

      _queue.CompleteAdding(); 

      Console.WriteLine("Waiting for all tasks to exit."); 
      Task.WaitAll(tasks); 

      Console.WriteLine("Finished waiting for all tasks. Press <return> to exit."); 
      Console.ReadLine(); 
     } 

     private void process(int id) 
     { 
      Console.WriteLine("Process {0} is starting.", id); 

      foreach (var item in _queue.GetConsumingEnumerable()) 
      { 
       Console.WriteLine("Process {0} is processing item# {1}", id, item); 
       Thread.Sleep(200); // Simulate long processing time. 
      } 

      Console.WriteLine("Process {0} is stopping.", id); 
     } 

     private static void Main() 
     { 
      new Program().run(); 
     } 
    } 
} 

Обратите внимание, что решающим здесь является то, что GetConsumingEnumerable() возвращает перечислимы, который будет блокировать, если нет элементов в очереди, но которые выйдет, если нет предметов и продюсер позвонил CompleteAdding(). Это упрощает управление, когда рабочие потоки завершаются.