Я наконец достиг многопоточного решения, используя BlockingCollection.Спасибо @Damien_The_Unbeliever за указание в правильном направлении.
Я думаю, что это был важный урок при работе с изображениями в многопоточной среде.Я узнал, что изображения очень уязвимы, когда делятся ими в разных потоках.
Как я уже писал в этом вопросе, здесь я должен сделать снимки с X разных веб-камер, показать их в X разных боксах изображений и, как быстроКак я могу (не прерывая частоту кадров показанного видео), выполнить обработку изображения вместо показа кадра в imageBox.При использовании BlockingCollection мне не нужно фиксировать частоту для обработки кадров, как я делал раньше (каждые 5 кадров).Теперь я могу показать кадр каждой камеры, если у меня уже есть кадр из этой камеры, добавленный в BlockingCollection.
Еще одна важная деталь, на которую следует обратить внимание, в документации .NET для BlockingCollection говорится, что по умолчаниюон реализует FIFO, так как это ConcurrentQueue на нижнем уровне, но я думаю, что это не так, поскольку мне пришлось самому определять его при создании экземпляра:
BlockingCollection<Tuple<int, Image>> tupleCollection = new BlockingCollection<Tuple<int, Image>>(new ConcurrentQueue<Tuple<int, Image>>(), X);
Как метод Take () может 'Для нацеливания на нужный элемент в коллекции мне пришлось использовать кортеж, чтобы узнать, к какой камере принадлежит кадр, и взять кадры, чтобы определить ConcurrentQueue.
Так что в основном псевдокод это:
void Main()
{
//Instantiate cameras
//Subscribe to the ImageGrabbed events of each (producers)
// A simple blocking consumer with no cancellation.
Task.Run(() => DetectFace());
}
producer1(sender, e)
{
//Get snapshot
...
if (!tupleCollection.Any(x => x.Item1 == 1))
{
tupleCollection.Add(new Tuple<int, Image>(1, snapshot));
}
else
imageBox1.Image = snapshot;
}
producer2(sender, e)
{
//Get snapshot
...
if (!tupleCollection.Any(x => x.Item1 == 2))
{
tupleCollection.Add(new Tuple<int, Image>(2, snapshot));
}
else
imageBox2.Image = snapshot;
}
...
producerX(sender, e)
{
//Get snapshot
...
if (!tupleCollection.Any(x => x.Item1 == X))
{
tupleCollection.Add(new Tuple<int, Image>(X, snapshot));
}
else
imageBoxX.Image = snapshot;
}
private void DetectFace()
{
while (true)
{
Tuple<int, Image> data = null;
try
{
data = tupleCollection.Take();
}
catch (InvalidOperationException) { }
if (data != null)
{
//image processing
}
}
}
В большинстве примеров, которые я обнаружил, для прекращения добавления и использования используются условия IsCompletedAdded и IsCompleted, но мне нужно, чтобы оно выполнялось вечно, поэтому оператор while (true).
Я использовал этот код 24/7 в течение последней недели, никаких ошибок в гонках на данный момент, и процессор сильно ограничен,поэтому я очень доволен этим решением и считаю, что оно правильное.