QThread, moveToThread() или другой подход?

Я разрабатываю приложение с графическим интерфейсом для многопоточной обработки видео. В результате я понял, что совершенно запутался в разных способах реализации потоков в 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, который бы обрабатывал сигналы, но стоит ли усложнять?

Я определенно смущен.

Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
0
53
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

То, что вы описываете, похоже, является проблемой производителя-потребителя. Многие документы доступны в Интернете.

У вас есть один поток для ввода-вывода и другой поток, который принимает эти кадры и обрабатывает их параллельно. Трубопровод может быть даже длиннее. Возможное решение для этого состоит в том, чтобы просто иметь подкласс QThread, который продолжает читать файл (как и вы) и помещает эти кадры в очередь, возможно, в очередь блокировки. Другой подкласс QThread извлекает кадры из очереди блокировки и выполняет их обработку. Если хотите, их может быть больше, и все они будут получать кадры из очереди.

Я написал это специально: https://github.com/carlonluca/lqtutils/blob/master/lqtutils_bqueue.h.

Конечно, существует множество других подходов.

Другие вопросы по теме