BlockingCollection, состояние гонки? - PullRequest
0 голосов
/ 24 марта 2012

Я реализовал шаблон Producer / Consumer, используя BlockingCollection, однако, похоже, он не блокируется, как я ожидаю.

У меня есть один поток, который получает кадры с веб-камеры и добавляет их в коллекцию BlockingCollection

private void video_NewFrame(object sender, NewFrameEventArgs eventArgs) {
    image = (Bitmap)eventArgs.Frame.Clone();
    queue.Add(image);
    if (NewFrame != null)
        NewFrame(this, new NewFrameEventArgs(image)); //invoke the event for display
}

А в другой ветке у меня есть ссылка на коллекцию и обработать фреймы, используя

public void Run() {
    foreach (Bitmap bmp in queue.GetConsumingEnumerable()) {
        // process bitmap

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

img http://i17.photobucket.com/albums/b52/orubap/2012-03-24_020858.png

Это не всегда происходит сразу, но я заметил, что это происходит только тогда, когда очередь пуста или почти пуста (т. Е. Потребитель быстрее, чем производитель), поэтому я предполагаю, что это как-то связано с первым добавленное изображение или последнее изображение. Есть идеи, почему это может происходить?

1 Ответ

0 голосов
/ 24 марта 2012

Поток, выполняющий video_NewFrame, использует изображение, когда оно передается в обработчик событий NewFrame. Поскольку он работает одновременно с Run, ничто не мешает двум потокам одновременно получить доступ к image. (Это произойдет только тогда, когда Run удалит изображение из очереди, когда обработчик событий NewFrame его обрабатывает, что объясняет, почему вы видите его только тогда, когда очередь пуста или почти пуста.)

Одним из исправлений может быть перевод звонка на NewFrame до queue.Add(image);video_NewFrame). Это гарантировало бы, что Run не сможет увидеть его, пока обработчик событий не закончит с ним (при условии, что обработчик событий не хранит ссылку на него).

...