Я работаю над проектом WPF с C # (.NET 4.0) для захвата последовательности из 300 видеокадров с высокоскоростной камеры, которую необходимо сохранить на диск (формат BMP). Видеокадры должны быть записаны с почти точными временными интервалами, поэтому я не могу сохранить кадры на диск по мере их захвата - дисковый ввод-вывод непредсказуем и отбрасывает временные интервалы между кадрами. Карта захвата имеет около 60 кадровых буферов.
Я не уверен, что лучший подход для реализации решения этой проблемы. Сначала я хочу создать поток «BufferToDisk», который сохраняет изображения из кадровых буферов по мере их появления. В этом сценарии основной поток захватывает буфер кадра и затем сигнализирует потоку, чтобы указать, что все в порядке, чтобы сохранить кадр. Проблема состоит в том, что кадры захватываются быстрее, чем поток может сохранить файлы, поэтому для их решения необходима какая-то синхронизация. Я думал, что семафор будет хорошим инструментом для этой работы. Я никогда не использовал Семафор таким образом, поэтому я не уверен, что делать дальше.
Это разумный подход к этой проблеме? Если да, может кто-нибудь выложить какой-нибудь код, чтобы я начал?
Любая помощь очень ценится.
Edit:
Просматривая связанный отрывок книги «Threading in C # - Part 2», я решил реализовать решение, адаптировав пример класса «ProducerConsumerQueue». Вот мой адаптированный код:
class ProducerConsumerQueue : IDisposable
{
EventWaitHandle _wh = new AutoResetEvent(false);
Thread _worker;
readonly object _locker = new object();
Queue<string> _tasks = new Queue<string>();
public ProducerConsumerQueue()
{
_worker = new Thread(Work);
_worker.Start();
}
public void EnqueueTask(string task)
{
lock (_locker) _tasks.Enqueue(task);
_wh.Set();
}
public void Dispose()
{
EnqueueTask(null); // Signal the consumer to exit.
_worker.Join(); // Wait for the consumer's thread to finish.
_wh.Close(); // Release any OS resources.
}
void Work()
{
while (true)
{
string task = null;
lock (_locker)
if (_tasks.Count > 0)
{
task = _tasks.Dequeue();
if (task == null)
{
return;
}
}
if (task != null)
{
// parse the parameters from the input queue item
string[] indexVals = task.Split(',');
int frameNum = Convert.ToInt32(indexVals[0]);
int fileNum = Convert.ToInt32(indexVals[1]);
string path = indexVals[2];
// build the file name
string newFileName = String.Format("img{0:d3}.bmp", fileNum);
string fqfn = System.IO.Path.Combine(path, newFileName);
// save the captured image to disk
int ret = pxd_saveBmp(1, fqfn, frameNum, 0, 0, -1, -1, 0, 0);
}
else
{
_wh.WaitOne(); // No more tasks - wait for a signal
}
}
}
}
Использование класса в основной процедуре:
// capture bitmap images and save them to disk
using (ProducerConsumerQueue q = new ProducerConsumerQueue())
{
for (int i = 0; i < 300; i++)
{
if (curFrmBuf > numFrmBufs)
{
curFrmBuf = 1; // wrap around to the first frame buffer
}
// snap an image to the image buffer
int ret = pxd_doSnap(1, curFrmBuf, 0);
// build the parameters for saving the frame to image file (for the queue)
string fileSaveParams = curFrmBuf + "," + (i + 1) + "," + newPath;
q.EnqueueTask(fileSaveParams);
curFrmBuf++;
}
}
Довольно гладкий класс - небольшое количество кода для этой функции.
Большое спасибо за предложения, ребята.