Я разрабатываю приложение с графическим интерфейсом для многопоточной обработки видео. В результате я понял, что совершенно запутался в разных способах реализации потоков в Qt и что мне нужна помощь, чтобы систематизировать знания, полученные из документации и довольно противоречивых статей (я следовал рекомендациям из нижней таблицы в этой статьи).
Идея такова: есть ReadingThread для чтения кадров из видео и ProcessingThread, где производится первичная обработка кадров и запускаются задачи с нужными алгоритмами обработки полученных кадров (наверное звучит слишком сложно, но вопрос не в этом). Оба объявления объявлены в основном потоке.
ReadingThread заполняет буфер кадрами из видеофайла. Этот поток унаследован от QThread: бесконечный цикл в run(), который заканчивается, когда заканчивается или останавливается видео. С этим потоком проблем нет, он работает именно так, как задумано. Указанные задачи реализованы в виде QRunnable, что меня тоже полностью устраивает. Но я не знаю, что делать со вторым потоком, который обрабатывает каждый кадр довольно долго.
Изначально я хотел снова наследовать QThread с бесконечным циклом, который бы поочередно обрабатывал изображения, полученные от ReadingThread:
void run() override
{
// some pseudocode
while(!isInterruptRequested)
{
if (!isImageInProcessing)
doSomeProcessing();
}
}
Но в этом случае слоты будут выполняться в основном потоке, где был инициализирован ProcessingThread. И это приводит к проблемам, потому что этот поток должен получать сигналы от других потоков. Очевидно, лучше использовать moveToThread(), но что мне делать в этом случае? Также использовать бесконечный цикл? Если да, то как? Или лучше создать новый Worker и перемещать его в поток для каждого нового кадра видео? Насколько это повлияет на производительность, если такой Worker окажется достаточно тяжелым, хранящим множество параметров обработки и все такое? Необходимость получать сигналы также мешает мне использовать QtConcurrent/QRunnable. Но это можно исправить двойным наследованием или добавлением эмиттерного QObject, который бы обрабатывал сигналы, но стоит ли усложнять?
Я определенно смущен.
То, что вы описываете, похоже, является проблемой производителя-потребителя. Многие документы доступны в Интернете.
У вас есть один поток для ввода-вывода и другой поток, который принимает эти кадры и обрабатывает их параллельно. Трубопровод может быть даже длиннее. Возможное решение для этого состоит в том, чтобы просто иметь подкласс QThread, который продолжает читать файл (как и вы) и помещает эти кадры в очередь, возможно, в очередь блокировки. Другой подкласс QThread извлекает кадры из очереди блокировки и выполняет их обработку. Если хотите, их может быть больше, и все они будут получать кадры из очереди.
Я написал это специально: https://github.com/carlonluca/lqtutils/blob/master/lqtutils_bqueue.h.
Конечно, существует множество других подходов.