Название: Параллельный поток Отправлено: Eugene K от Декабрь 16, 2019, 23:02 Есть поток, где идет обработка данных параллельно основному потоку.
При обработке данных должна быть возможность нажимать на кнопки в программе. Код: //класс параллельного потока обработки данных При работе программы параллельный поток обработки данных замораживает окно программы и кнопки невозможно нажимать. Где я допустил неточность? Название: Re: Параллельный поток Отправлено: Авварон от Декабрь 16, 2019, 23:32 Где я допустил неточность? Грубо говоря - везде. Чуть точнее: an_t21() вызывается в _главном_ потоке. Еще чуть точнее - выкиньте всё нафиг, опишите что вам надо словами сюда и вам скажут как делать правильно. ЗЫ: никогда, никогда не наследуйте QThread для реализации бизнес-логики, тем более не наследуйте от нее окно. Название: Re: Параллельный поток Отправлено: Eugene K от Декабрь 17, 2019, 05:39 Если словами, то на Qt4.1 (Windows) мне надо организовать четыре параллельных потока: первый принимает данные по сети, второй - обрабатывает эти данные, третий - вычисляет и фильтрует обработанные данные, четвертый - передает отфильтрованные данные по сети дальше.
При этом во время действия этих потоков, оператор может нажимать на кнопки в программе, чтобы смотреть другие окна программы или остановить прием, обработку, вычисление и передачу данных. Т.е. вопрос в том как мне правильно организовать четыре параллельных потока для этого. Название: Re: Параллельный поток Отправлено: qate от Декабрь 17, 2019, 08:46 Qt4.1 вышло в 2012 г. - какая причина использовать эту версию ?
> мне надо организовать четыре параллельных потока: первый принимает данные по сети, второй - обрабатывает эти данные, третий - вычисляет и фильтрует обработанные данные, четвертый - передает отфильтрованные данные по сети дальше. прием и передачу не надо пихать в отдельные потоки - работай по событиям для второго и третьего используй https://doc.qt.io/qt-5/qtconcurrentrun.html если так не пойдет - опиши почему ? Название: Re: Параллельный поток Отправлено: Авварон от Декабрь 17, 2019, 13:22 Если словами, то на Qt4.1 (Windows) мне надо организовать четыре параллельных потока: первый принимает данные по сети, второй - обрабатывает эти данные, третий - вычисляет и фильтрует обработанные данные, четвертый - передает отфильтрованные данные по сети дальше. При этом во время действия этих потоков, оператор может нажимать на кнопки в программе, чтобы смотреть другие окна программы или остановить прием, обработку, вычисление и передачу данных. Т.е. вопрос в том как мне правильно организовать четыре параллельных потока для этого. Откуда требование в 4 потока? Начните с однопоточного варианта, но с задумкой распараллелить, как сказано выше через QtConcurrent. Начните с воркера-приемщика, положите туда сокет, сделайте там начальную валидацию данных, когда пришел чанк, достаточный для обработки, вызывайте функцию обработки. Функция обработки должна быть свободной (или статической функцией), но отдельной от класса-приемщика, принимающая данные и возвращающая обработанные данные. Так ее можно будет легко завернуть в QtConcurrent. Аналогично, фильтрация - свободная функция, принимает выход от обработчика. Дальше, сделайте воркер-отправщик, принимающий слотом фильтрованные данные. Теперь как это все подружить - сперва сделайте всё в главном потоке. Вероятно, будет тормозить обработка - сперва проверьте, что это так (либо через профилировщик, либо QElapsedTimer вставьте). Если тормозит обработка, выносите ее в поток(и) через QtConcurrent - я бы на обработку+фильтрацию делал одну задачу, но, в зависимости от объема данных, можно использовать и MapReduce. Делать отдельно обработку и фильтрацию не надо - у вас и так будет параллельно может исполнятся несколько задач обработки+фильтраци.и Результат от задачи получайте через QFutureWatcher в том же главном потоке. Если тормозит прием по сети (хотя вряд ли), можно завести объект QThread (не наследоваться!) и переместить приемщик, отправщик и FutureWatcher туда. Если у вас всё правильно разделено в однопоточном варианте, то проблем добавить тред не возникнет - это дело 10 строк (start, 3*moveToThread, 3*connect(&QThread::finished), quit, stop) Название: Re: Параллельный поток Отправлено: Igors от Декабрь 17, 2019, 14:33 А не лучше ли задействовать QThreadPool скармливая ему возникающие задачи?
Название: Re: Параллельный поток Отправлено: Авварон от Декабрь 17, 2019, 14:42 А не лучше ли задействовать QThreadPool скармливая ему возникающие задачи? конкаррент именно это и делает Название: Re: Параллельный поток Отправлено: Igors от Декабрь 17, 2019, 14:52 конкаррент именно это и делает Он больше озабочен распределением задач, вычисляет размер "пачки" и.т.п., а здесь это не актуально Название: Re: Параллельный поток Отправлено: Авварон от Декабрь 17, 2019, 14:59 конкаррент именно это и делает Он больше озабочен распределением задач, вычисляет размер "пачки" и.т.п., а здесь это не актуально QtConcorrent::run ничего не распределяет и не вычисляет. Он лишь избавляет от секса с голыми указателями, мьютексами и наследованием раннаблов. Название: Re: Параллельный поток Отправлено: Igors от Декабрь 17, 2019, 15:50 QtConcorrent::run ничего не распределяет и не вычисляет. Это не так, он задумывался как аналог tbb или OpenMP с ключом schedule dynamic. Сначала он дает нитке одну задачу и после завершения анализирует время выполнения. Потом нитка может получить уже 2 (или 10) задач или опять одну, там довольно длинная песня, смысл - оптимально распределить нагрузку. Название: Re: Параллельный поток Отправлено: Авварон от Декабрь 17, 2019, 16:10 Шта? Вы где это в коде (https://code.woboq.org/qt5/qtbase/src/concurrent/qtconcurrentrun.h.html#_ZN12QtConcurrent3runEPFT_vE) увидели?
Название: Re: Параллельный поток Отправлено: Igors от Декабрь 17, 2019, 17:33 Шта? Вы где это в коде (https://code.woboq.org/qt5/qtbase/src/concurrent/qtconcurrentrun.h.html#_ZN12QtConcurrent3runEPFT_vE) увидели? Вот "видимая часть" айсберга, см также timeBefore/timeAfterКод
Название: Re: Параллельный поток Отправлено: Авварон от Декабрь 17, 2019, 17:59 Шта? Вы где это в коде (https://code.woboq.org/qt5/qtbase/src/concurrent/qtconcurrentrun.h.html#_ZN12QtConcurrent3runEPFT_vE) увидели? Вот "видимая часть" айсберга, см также timeBefore/timeAfterОтлично, где в QtConcurrent::run это используется? Это используется в QtConcurrent::map, ну да и бог с ним, я же написал ровно что и вы - сперва попробовать следать через run() который (https://code.woboq.org/qt5/qtbase/src/concurrent/qtconcurrentrun.h.html#74) тот (https://code.woboq.org/qt5/qtbase/src/concurrent/qtconcurrentstoredfunctioncall.h.html#QtConcurrent::StoredFunctorCall0) же (https://code.woboq.org/qt5/qtbase/src/concurrent/qtconcurrentrunbase.h.html#QtConcurrent::RunFunctionTask) раннабл (https://code.woboq.org/qt5/qtbase/src/concurrent/qtconcurrentrunbase.h.html#QtConcurrent::RunFunctionTaskBase) Название: Re: Параллельный поток Отправлено: Eugene K от Декабрь 17, 2019, 23:55 Пробую использовать moveToThread(thread)
но при создании объекта thread=new QThread() компилятор ругается: cannot allocate an object of type 'QThread' because the following virtual functions are abstract: error: virtual void QThread::run() Название: Re: Параллельный поток Отправлено: Авварон от Декабрь 18, 2019, 00:22 Твою ж, у вас 4.1 >:( Точно никак поновее нельзя взять?
Ладно, делать нечего - надо отнаследоваться от треда и в своем run() тупо вызвать exec(), как сделано (https://code.woboq.org/qt5/qtbase/src/corelib/thread/qthread.cpp.html#_ZN7QThread3runEv) в более новых версиях Название: Re: Параллельный поток Отправлено: Eugene K от Декабрь 18, 2019, 00:35 В 4.1 есть moveToThread(). его можно как-то использовать? все таки не просто так он должен быть.
Название: Re: Параллельный поток Отправлено: Авварон от Декабрь 18, 2019, 00:50 В 4.1 есть moveToThread(). его можно как-то использовать? все таки не просто так он должен быть. Да, я же говорю - надо, чтобы нитка крутила event loop. К сожалению, кутешники не сразу придумали как делать (https://doc.qt.io/qt-5/qthread.html#details) грамотно и до 4.4 метод run() был чисто виртуальным, поэтом без наследования было никак (а я уж и запамятовал). Но фиксится это тривиально - тупо вызываете exec() внутри run() и всё - это ровно то, что делает QThread начиная с 4.4 и поэтому этот "новый" класс наследовать не надо. В общем случае, наследоваться от треда плохо, потому что туда начинают писать бизнес-логику и размывается граница что где, то есть какой метод в каком потоке зовется. Когда есть разделение на Worker и QThread с exec'ом всё очевидно - методы треда (start, quit) зовутся из главного потока, методы Worker'а зовутся из потока QThread'а. С главным потоком Worker общается через сигнал-слоты. То есть, есть разделение по данным => не надо явных мьютексов и иных механизмов синхронизации. То есть вам нужен такой хелпер Код: struct Thread: public Thread А дальше всё как в примере с воркером Название: Re: Параллельный поток Отправлено: Eugene K от Декабрь 18, 2019, 02:12 Cделал так:
frmMain.h: Код: struct Thread: public QThread frmMain.cpp (главная форма и главное окно): Код: frmMain::frmMain() : QWidget(0, Qt::Window) все равно главное окно заморожено Название: Re: Параллельный поток Отправлено: qate от Декабрь 18, 2019, 10:02 В 4.1 есть moveToThread(). его можно как-то использовать? все таки не просто так он должен быть. Но зачем использовать старое и высохшее 4.1 ? Найдется там еще баг и как с этим жить ? Название: Re: Параллельный поток Отправлено: Авварон от Декабрь 18, 2019, 12:33 Cделал так: Вы упорно продолжаете игнорировать совет использовать отдельного воркера :( Код: this->moveToThread(&thread1); И в этом не было бы ничего плохого, кроме того, что опять не понятно, в каком потоке какой метод должен вызываться (и ваши проблемы это подтверждают). Вот например, вы переместили окно в тред и теперь все слоты (по идее) должны вызываться в потоке. В том числе count1(), который стартует поток. Но ведь поток еще на запущен! Вопрос - в каком потоке вызовется этот слот (и вызовется ли?). Я не знаю, дебагать неправильно написанный код мне лень. Еще, возможно, ваше окно вообще никуда не переместилось, потому что виджеты нельзя перемещать в треды (by design они должны жить в главном потоке). В консоли вы должны видеть что-то типа Цитировать QObject::moveToThread: Widgets cannot be moved to a new thread Название: Re: Параллельный поток Отправлено: Eugene K от Декабрь 18, 2019, 13:35 Авварон, я не игнорирую совет, я не знаю пока как использовать отдельного воркера.
Я и написал сюда, потоиу, что с потоками не знаком как оказалось. Раньше работал через потоки таймеров и другого не надо было. Вы на меня не тратьте много времени, а то мне уже неудобно, лучше приведите работающий фрагмент создания параллельного потока типа нажал на кнопку - на экране печатается текст с паузами и в это время можно другие кнопки нажимать (как из моего фрагмента выше). Мне надо создать хотя бы один работающий поток для начала, дальше, думаю, разберусь. А то примеры из интернета то ошибки выдают, то не работают. Возможно дело в версии 4.1. Версию 4.1 использую по старинке, не было времени переходить на новую. Не знал, что будут такие проблемы. На крайний случай придется на 4.8 переходить, т.к. QtConcurrent с 4.7 идет. Но это надо будет адаптировать программу, а написано немало. Название: Re: Параллельный поток Отправлено: Igors от Декабрь 18, 2019, 15:06 Вы на меня не тратьте много времени, а то мне уже неудобно, лучше приведите работающий фрагмент создания параллельного потока типа нажал на кнопку - на экране печатается текст с паузами и в это время можно другие кнопки нажимать (как из моего фрагмента выше). Ну ладно, купили на "неудобно" :) Аттач. Там нет завершения нитки (разберетесь). Старый синтаксис SLOT/SIGNAL оставил, но если что другое не пойдет на древней версии - проблемы Ваши. Заметьте что нитки должны общаться только сигналами, не пытайтесь лезть к виджетам напрямую из воркера - это рухнет. Ну и если "по-взрослому" то, как сказали выше, никакие QThread здесь не нужны, лучше заюзать штатный тул который сам их сделаетМне надо создать хотя бы один работающий поток для начала, дальше, думаю, разберусь. Ох уж это "программирование на примерах" :)Название: Re: Параллельный поток Отправлено: qate от Декабрь 18, 2019, 16:08 Версию 4.1 использую по старинке, не было времени переходить на новую. какая выдержка и терпение ! Название: Re: Параллельный поток Отправлено: kambala от Декабрь 18, 2019, 16:38 этой версии наверное уже лет 10, если не больше? :)
Название: Re: Параллельный поток Отправлено: Авварон от Декабрь 18, 2019, 16:43 этой версии наверное уже лет 10, если не больше? :) Больше, я когда пытался вчера по исходникам найти когда же там run перестал быть виртуальным, выяснил что это было в 4.4, а история в гите начинается с 4.5 в 2009м году. То есть 10-11 лет - это 4.5, а то мамонтово еще древнее ;) Название: Re: Параллельный поток Отправлено: ViTech от Декабрь 18, 2019, 17:51 этой версии наверное уже лет 10, если не больше? :) Qt_version_history Qt_4 (https://en.wikipedia.org/wiki/Qt_version_history#Qt_4): 4.1 - 20 December 2005. Через пару дней паспорт получать может :). Название: Re: Параллельный поток Отправлено: Eugene K от Декабрь 18, 2019, 20:22 .
Название: Re: Параллельный поток Отправлено: Авварон от Декабрь 18, 2019, 20:46 Боже, ну неужели так самому самому допилить. Проверьте вариант в аттаче
|