2013-04-10 2 views
3

Я понимаю, что BlockingCollection использованием ConcurrentQueue имеет boundedcapacity 100.BlockingCollection Максимальный размер

Однако я не уверен относительно того, что это значит.

Я пытаюсь достичь параллельного кеша, который может деактивировать, может декомпрессироваться/зависнуть в одной операции, если размер очереди слишком велик (т. Е. Потерять сообщения при переполнении кеша). Есть ли способ использовать ограниченную емкость для этого или лучше вручную сделать это или создать новую коллекцию.

В основном у меня есть нить для чтения и несколько писем. Я бы хотел, чтобы данные в очереди были «самыми свежими» из всех авторов.

+0

Может быть, вам нужно любопытное событие, чтобы сообщить писателям о самых свежих данных? –

ответ

1

Ограниченная емкость N означает, что если в очереди уже содержится N элементов, любой поток, пытающийся добавить другой элемент, будет блокироваться до тех пор, пока другой поток не удалит элемент.

Возможно, вам нужна другая концепция: вы хотите, чтобы последний элемент был первым элементом, который был отменен потребляющей нитью.

Вы можете достичь этого, используя ConcurrentStack, а не ConcurrentQueue для базового хранилища.

Вы должны использовать this constructor и пройти в ConcurrentStack.

Например:

var blockingCollection = new BlockingCollection<int>(new ConcurrentStack<int>()); 

Используя ConcurrentStack, вы убедитесь, что каждый элемент, что потребляющие нить dequeues будет свежайшая элемент в очереди в то время.

Также обратите внимание, что если вы укажете верхнюю границу для блокирующей коллекции, вы можете использовать BlockingCollection.TryAdd(), которая вернет false, если коллекция была заполнена в тот момент, когда вы ее назвали.

+0

на основе моего самого свежего заявления, которое верно. однако я все равно хочу, чтобы очередь была отправлена ​​в том порядке, в котором они находятся в очереди. Похоже, что лучше всего сделать if (q.count> x) {q.take(); // donothing} q.add (newitem) перед каждым добавлением, чтобы сохранить размер вниз, однако если другой поток принимает после того, как длина подсчитывается, тогда вы в конечном итоге удаляете сообщение без необходимости – maxfridbe

+0

Хм, я не думаю, что я действительно правильно понимаю ваши требования ... Но если вы укажете верхнюю границу для блокирующей коллекции, вы можете использовать ['BlockingCollection. TryAdd() '] (http://msdn.microsoft.com/en-us/library/dd267245.aspx), и он вернет false, если очередь заполнена - можете ли вы ее использовать? –

2

Это звучит так, как будто вы пытаетесь построить что-то вроде MRU (наиболее используемого) кеша. BlockingCollection - не лучший способ сделать это.

Я бы предложил вместо этого использовать LinkedList. Это не потокобезопасно, поэтому вам придется предоставить свою собственную синхронизацию, но это не слишком сложно. Ваш Епдиеие метод выглядит следующим образом:

LinkedList<MyType> TheQueue = new LinkedList<MyType>(); 
object listLock = new object(); 

void Enqueue(MyType item) 
{ 
    lock (listLock) 
    { 
     TheQueue.AddFirst(item); 
     while (TheQueue.Count > MaxQueueSize) 
     { 
      // Queue overflow. Reduce to max size. 
      TheQueue.RemoveLast(); 
     } 
    } 
} 

И Dequeue еще проще:

MyType Dequeue() 
{ 
    lock (listLock) 
    { 
     return (TheQueue.Count > 0) ? TheQueue.RemoveLast() : null; 
    } 
} 

Это немного сложнее, если вы хотите, чтобы потребители могли сделать незанятое ожидание в очереди. Вы можете сделать это с Monitor.Wait и Monitor.Pulse. См. Пример на странице Monitor.Pulse для примера.

Update:

Это происходит со мной, что вы могли бы сделать то же самое с кольцевым буфером (массив). Просто поддерживайте указатели головы и хвоста. Вы указываете на head и удаляете по адресу tail. Если вы переходите к вставке и head == tail, вам необходимо увеличить tail, что эффективно удаляет предыдущий пункт tail.

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