U
UrekMazin020 августа 2020 г. 14:19

Работа с потоками с помощью QtConcurentRun

C++, OpenCV, Qt, QtConcurrent

Доброе время суток. Создаю pet-project. Суть программы в визуализации функций OpenCV. Работа будет вестись с псевдо-видео с камеры.
По кнопке Start стартует функция, в которой проходит работа с классом OpenCV и отрисовка картинки с камеры на QLabel. Отрисовка происходит в бесконечном цикле while(isRun). Очевидно что он забирает на себя основной поток, после чего весь виджет зависал и кнопка Stop {isRun=false} была бесполезна. Стало очевидно что программу нужно делать многопоточной, ибо от while никак не отказаться.

Мне подсказали сделать так:

По кнопке старт 
    isRun = true;
    QtConcurrent::run([this]{
        while(isRun)
        {
            static int count = 0;
            ...
            qDebug() << "task: " << (count++);
        }
    });
По кнопке стоп
   isRun = false;

Я так сделал и всё заработало, вот только кнопка Start работала только один раз, после чего заново не запускалась никак. Я решил проверить и немножко добавил в код:

 По кнопке старт 
    isRun = true;
    QtConcurrent::run([this]{
        while(isRun)
        {
            static int count = 0;
            ...
            qDebug() << "task: " << (count++);
        }
        qDebug() << "One" << endl;   // ДОБАВЛЕНО
    });
    QDebug() << "Two" << endl;       // ДОБАВЛЕНО

По кнопке старт выводится Two, на стоп One

Объясните пожалуйста, как работает функция QtConcurrent::run, и почему числа выводятся в такой последовательности. Будет круто если дадите ссылку на хорошие статьи об QtConcurrent, я к сожалению не нашёл даже на английском. Ещё лучше если скажете как сделать что бы "Start" работал больше одного раза =-)
UPD. Тут крутое оформление сайта))
Фото кода, аккуратно, много мусора:

Рекомендуем хостинг TIMEWEB
Рекомендуем хостинг TIMEWEB
Стабильный хостинг, на котором располагается социальная сеть EVILEG. Для проектов на Django рекомендуем VDS хостинг.

Вам это нравится? Поделитесь в социальных сетях!

11
Алексей Внуков
  • 20 августа 2020 г. 15:21

я делал чуть по другому, в отдельном потоке запускал цикл обработки камеры, а потом каждый фрейм cv::Mat отправлял сигналом в нужные потоки (один поток выводил видео, второй делал обработку видео).
а QtConcurrent::run не предназначен для бесконечного цикла, он для обработки какого-то временного процесса, результат которого вам понадобится, наприме есть сложное математическое вычисление которое занимает время и ресурсы, для того чтоб сделать разово вычисление в другом потоке не целесообразно под него выделять целый тред, поэтому для него существует QtConcurrent::run, который создаст поток выполнит функцию, вернет значение и закроет поток

    U
    • 20 августа 2020 г. 15:50
    • (ред.)

    Понял, спасибо. У вас не осталось проекта на гитхабе, где можно будет прочитать код с правильной реализацией? Если проект был коммерческим и вы не можете его показать, то я пойму. Каким способом вы реализовали потоки?

      Алексей Внуков
      • 20 августа 2020 г. 16:10
      • (ред.)
      • Ответ был помечен как решение.

      та там показывать особо нечего, просто найти нужно. все по класике делаем рабочий класс, через QThread создаем поток, обьект класса делаем moveToThread. в отдельной функции делаем потоку старт, в конекте пишем что по сигналу от потока started, запускаем в рабочем класе функцию с бесконечным циклом получения кадров с камеры, каждый новый кадр через сигнал отправляем в нужное место, в параметре сигнала указываем cv::Mat,для корректной работы сигналов и чтоб не было адцкой загрузки проца в конце бесконечного цикла добавляем qApp->processEvents(); и QThread::msleep(10);
      п.с. в общем и все. пишите пробуйте, если что спрашивайте. вот как работать с потоками QThread , только учитите сейчас правильным считается делать moveToThread, по ссылке есть старый способ переопределение run(), и наследование от QThread - но это не правильно и морально устарело.

        U
        • 20 августа 2020 г. 16:18

        Если я вас понял, правильным считается создание потока QThread и последующее moveToThread, а не наследование от QThread и переопределение run.

        Спасибо, благодаря вам понял свою проблему. Буду писать и пробовать :-)

          Алексей Внуков
          • 20 августа 2020 г. 16:28

          да, поняли правильно

            Алексей Внуков
            • 20 августа 2020 г. 16:32

            и не забудьте cv::Mat зарегистрировать как тип данных, иначе приложение может падать во время сигнала и в описании ошибки будет вам говорить что cv::Mat нужно зарегистрировать

              U
              • 20 августа 2020 г. 17:03
              • (ред.)

              Извините что опять спрашиваю, а что подразумевается под "зарегестрировать переменную "? Этот момент не очень ясен

                Алексей Внуков
                • 20 августа 2020 г. 17:45

                cv::Mat это не тип данных Qt, а opencv, поэтому Qt не знает о нем. чтоб нормально работали сигналы/слоты с не стандартными типами нужно их зарегистрировать. для этого в main:

                Q_DECLARE_METATYPE(cv::Mat)
                
                int main(int argc, char *argv[])
                {
                    ...
                    qRegisterMetaType<cv::Mat>("cv::Mat");
                    ...
                }
                
                  Ruslan Polupan
                  • 21 августа 2020 г. 1:08

                  Может это вам поможет https://evileg.com/ru/post/424/

                    U
                    • 21 августа 2020 г. 7:56
                    • (ред.)

                    Да, спасибо, как наглядный пример очень даже

                      U
                      • 21 августа 2020 г. 7:57

                      Спасибо, действительно помогло

                        Комментарии

                        Только авторизованные пользователи могут публиковать комментарии.
                        Пожалуйста, авторизуйтесь или зарегистрируйтесь
                        e
                        • ehot
                        • 1 апреля 2024 г. 0:29

                        C++ - Тест 003. Условия и циклы

                        • Результат:78баллов,
                        • Очки рейтинга2
                        B

                        C++ - Тест 002. Константы

                        • Результат:16баллов,
                        • Очки рейтинга-10
                        B

                        C++ - Тест 001. Первая программа и типы данных

                        • Результат:46баллов,
                        • Очки рейтинга-6
                        Последние комментарии
                        k
                        kmssr9 февраля 2024 г. 5:43
                        Qt Linux - Урок 001. Автозапуск Qt приложения под Linux как сделать автозапуск для флэтпака, который не даёт создавать файлы в ~/.config - вот это вопрос ))
                        АК
                        Анатолий Кононенко5 февраля 2024 г. 12:50
                        Qt WinAPI - Урок 007. Работаем с ICMP Ping в Qt Без строки #include <QRegularExpressionValidator> в заголовочном файле не работает валидатор.
                        EVA
                        EVA25 декабря 2023 г. 21:30
                        Boost - статическая линковка в CMake проекте под Windows Ошибка LNK1104 часто возникает, когда компоновщик не может найти или открыть файл библиотеки. В вашем случае, это файл libboost_locale-vc142-mt-gd-x64-1_74.lib из библиотеки Boost для C+…
                        J
                        JonnyJo25 декабря 2023 г. 19:38
                        Boost - статическая линковка в CMake проекте под Windows Сделал всё по-как у вас, но выдаёт ошибку [build] LINK : fatal error LNK1104: не удается открыть файл "libboost_locale-vc142-mt-gd-x64-1_74.lib" Хоть убей, не могу понять в чём дел…
                        G
                        Gvozdik19 декабря 2023 г. 8:01
                        Qt/C++ - Урок 056. Подключение библиотеки Boost в Qt для компиляторов MinGW и MSVC Для решения твой проблемы добавь в файл .pro строчку "LIBS += -lws2_32" она решит проблему , лично мне помогло.
                        Сейчас обсуждают на форуме
                        a
                        a_vlasov14 апреля 2024 г. 16:41
                        Мобильное приложение на C++Qt и бэкенд к нему на Django Rest Framework Евгений, добрый день! Такой вопрос. Верно ли следующее утверждение: Любое Android-приложение, написанное на Java/Kotlin чисто теоретически (пусть и с большими трудностями) можно написать и на C+…
                        Павел Дорофеев
                        Павел Дорофеев14 апреля 2024 г. 12:35
                        QTableWidget с 2 заголовками Вот тут есть кастомный QTableView с многорядностью проект поддерживается, обращайтесь
                        f
                        fastrex4 апреля 2024 г. 14:47
                        Вернуть старое поведение QComboBox, не менять индекс при resetModel Добрый день! У нас много проектов в которых используется QComboBox, в версии 5.5.1, когда модель испускает сигнал resetModel, currentIndex не менялся. В версии 5.15 при resetModel происходит try…
                        P
                        Pisych27 февраля 2023 г. 15:04
                        Как получить в массив значения из связанной модели? Спасибо, разобрался:))
                        AC
                        Alexandru Codreanu19 января 2024 г. 22:57
                        QML Обнулить значения SpinBox Доброго времени суток, не могу разобраться с обнулением значение SpinBox находящего в делегате. import QtQuickimport QtQuick.ControlsWindow { width: 640 height: 480 visible: tr…

                        Следите за нами в социальных сетях