Russian Qt Forum

Qt => Вопросы новичков => Тема начата: Nidxogg от Сентябрь 23, 2014, 18:17



Название: Длительные операции + QtConcurrent
Отправлено: Nidxogg от Сентябрь 23, 2014, 18:17
Добрый день.

Есть gui-программа, работающая с БД. Все запросы и т.д вынесены в отдельный класс.
Все работает в одном потоке.

Есть такой псевдокод, который должен выполнится строго в заданной последовательности.
Код:
void MyClass::myMethod()
{
    func1();
    func2();
    func3();
}

Собственно func2() выполняется довольно долго, поэтому решил на время фриза интерфейса добавить гифку-прогрессбар(+QMovie) .
Гифка, естественно, не анимируется в процессе выполнения func2(). processEvent() не помог.

Тогда решил выполнить func2() в отдельном потоке с использованием QtConcurrent::run(...), гифка ожила, но теперь func3() начинает выполняться до окончания func2();
Пробовал использовать waitForFinished, но опять столкнулся с фризом интерфейса.

Может у кого-нибудь есть идеи как выйти из ситуации?



Название: Re: Длительные операции + QtConcurrent
Отправлено: Bepec от Сентябрь 23, 2014, 18:22
Видимо вы как то не так делали processEvents :) Всё должно работать без фризов.


Название: Re: Длительные операции + QtConcurrent
Отправлено: Old от Сентябрь 23, 2014, 18:23
Запускайте func3 в слоте, который будет вызываться при завершении потока, выполняющего func2.


Название: Re: Длительные операции + QtConcurrent
Отправлено: Nidxogg от Сентябрь 23, 2014, 18:44
Цитировать
Запускайте func3 в слоте, который будет вызываться при завершении потока, выполняющего func2.
Вы имеет ввиду соединить сигнал finished() от QFutureWatcher со слотом, и вызывать func3() там?

прим.: мне приходит несколько пакетов по сети практически одновременно, которые необходимо обработать.
В слоте я вызываю myMethod и рассчитываю, что обработка следующего пакета не начнется, пока не завершится обработка текущего (собственно так и работает, т.к все в одном потоке(если без QtConcurent)).  
Не получился ли, что я вызову myMethod раньше, чем завершится выполнение func3()?


Цитировать
Видимо вы как то не так делали processEvents Всё должно работать без фризов.
У меня прозрачный виджет ставится, аналог вашего sbglass (qlightboxwidget в гугле), на который кидается QLabel и гифка.
processEvents вызываю qApp->processEvents() во время обработки запроса из БД  (Порядка 150 раз в течение ~5 секунд);


Название: Re: Длительные операции + QtConcurrent
Отправлено: Igors от Сентябрь 23, 2014, 18:52
Гифка, естественно, не анимируется в процессе выполнения func2(). processEvent() не помог.
Не вижу здесь ничего естественного, надо разбираться. Вообще запуск потока только с целью обеспечить индикатор не есть хорошо/грамотно.


Название: Re: Длительные операции + QtConcurrent
Отправлено: Nidxogg от Сентябрь 23, 2014, 19:25
Цитировать
Не вижу здесь ничего естественного, надо разбираться
Главный поток загружен операциями в func2, интерфейс зафрижен.
Что не так?


Название: Re: Длительные операции + QtConcurrent
Отправлено: Bepec от Сентябрь 23, 2014, 20:58
Не так, что достаточно 25 раз в секунду вызывать processEvents чтобы пользователь вообще ничего не заподозрил.
Значит вы его вызываете или не там, или не так :)

Т.е. вот такое высказывание верно:
Главный поток загружен операциями в func2, где вызывается processEvents, интерфейс работает нормально.


Название: Re: Длительные операции + QtConcurrent
Отправлено: VPS от Сентябрь 23, 2014, 22:58
Что Вам мешает все три метода обработки данных запускать последовательно в отдельном потоке, а принимаемые пакеты из главного (GUI или другого) потока передавать туда на обработку? В данном случае, для передачи пакетов, можно попробовать использовать сигналы или библиотеку, в которой есть потокобезопасная очередь. Т.е. получится что-то типа шаблона Producer-Consumer.


Название: Re: Длительные операции + QtConcurrent
Отправлено: Igors от Сентябрь 24, 2014, 06:19
Главный поток загружен операциями в func2, интерфейс зафрижен.
Что не так?
А что "так"? :) То что есть интенсивный расчет - еще не основание выносить его в отдельный поток. Вот напр если 2 расчета параллельно - тогда да. А так гораздо проще вызывать processEvents в теле расчета. 25 раз в сек - ну это для видео, а для UI достаточно и 5 раз. Попробуйте вместо гифки напр QProgressDialog, убедитесь что он работает, а потом и до гифки дело дойдет.


Название: Re: Длительные операции + QtConcurrent
Отправлено: qate от Сентябрь 24, 2014, 11:40
QtConcurrent::run(myMethod) - не ?
вызывать руками процессевентс - это самому себе грабли раскидывать


Название: Re: Длительные операции + QtConcurrent
Отправлено: OKTA от Сентябрь 24, 2014, 12:08
Если планируется расширение в дальнейшем, то вынеси весь класс работы с БД в отдельный поток и не мучайся, а то так или processEvents везде распихивать или QtConcurrent::run постоянно дергать, если появятся новые тяжелые функции.


Название: Re: Длительные операции + QtConcurrent
Отправлено: Old от Сентябрь 24, 2014, 12:34
или QtConcurrent::run постоянно дергать, если появятся новые тяжелые функции.
Ну так он именно для этого и сделан. :)
Он запускает пул потоков и нагружает их когда в этом есть необходимость.


Название: Re: Длительные операции + QtConcurrent
Отправлено: OKTA от Сентябрь 24, 2014, 12:38
Так-то да, но когда их много, могут быть проблемы с управлением  :)


Название: Re: Длительные операции + QtConcurrent
Отправлено: Old от Сентябрь 24, 2014, 12:40
Так-то да, но когда их много, могут быть проблемы с управлением  :)
Проблемы с управлением могут быть только когда написано так, что есть проблемы с управлением, а так проблем с управлением быть не должно. :)


Название: Re: Длительные операции + QtConcurrent
Отправлено: OKTA от Сентябрь 24, 2014, 12:49
Это в идеальном варианте  :)
А так, например большая проблема QtConcurrentRun, что не остановишь его человеческим способом, когда потребуется. Вызывает геморрой, которого можно избежать, выделив все это барахло в честный отдельный поток  :)
Во всяком случае лично меня всегда это коробило и я стараюсь пользоваться QtConucrrentRun только в случае небольших функций  :)


Название: Re: Длительные операции + QtConcurrent
Отправлено: Old от Сентябрь 24, 2014, 12:56
А так, например большая проблема QtConcurrentRun, что не остановишь его человеческим способом, когда потребуется.
Все останавливается точно так же как и с отдельным потоком, через флажочек. :)


Название: Re: Длительные операции + QtConcurrent
Отправлено: OKTA от Сентябрь 24, 2014, 13:14
Флажочек да, без него никуда. Но лично меня большое количество QtConcurrent настораживает и пугает. Превращается в какой-то зоопарк, за которым тяжко следить и тем более разбираться в коде.  :) Про случай, когда надо мильён одинаковых функций вызвать в отдельных потоках я не говорю.
В общем, субъективно это все  ;D


Название: Re: Длительные операции + QtConcurrent
Отправлено: Nidxogg от Сентябрь 24, 2014, 18:07
С processEvents()  решил проблему
Оказалось, случайно, не в тот цикл его вставил (с малым число итераций)


Цитировать
Если планируется расширение в дальнейшем, то вынеси весь класс работы с БД в отдельный поток и не мучайся, а то так или processEvents везде распихивать или QtConcurrent::run постоянно дергать, если появятся новые тяжелые функции.
Так изначально и планировалось, но не пошло по некоторым причинам.

Цитировать
QtConcurrent::run(myMethod) - не ?
Мне его иногда приходится вызывать чаще, чем он успевает отработать.
Разве что создать какую-то очередь на обработку или мьютексами обложить

Цитировать
вызывать руками процессевентс - это самому себе грабли раскидывать
?


Название: Re: Длительные операции + QtConcurrent
Отправлено: qate от Сентябрь 25, 2014, 09:20

Цитировать
вызывать руками процессевентс - это самому себе грабли раскидывать
?

если обработчики сигналов не реентерабельны - будут проблемы


Название: Re: Длительные операции + QtConcurrent
Отправлено: Igors от Сентябрь 25, 2014, 10:43
если обработчики сигналов не реентерабельны - будут проблемы
Возможно имелось ввиду что processEvents разрешает др события/сигналы которые могут изменить контекст расчета, а то и вовсе удалить используемые в расчете данные. Да, от этого надо страховаться (часто модальностью) - но это так же и в др случаях.
..то вынеси весь класс работы с БД в отдельный поток и не мучайся, а то так или processEvents везде распихивать
И что изменит этот вынос? События-то все равно разрешены, теперь потому что главная нитка свободна. И все равно надо знать "а что же там с расчетом", поэтому что-то пихать в него все равно надо.


Название: Re: Длительные операции + QtConcurrent
Отправлено: OKTA от Сентябрь 25, 2014, 10:54
Да, пихать надо, но с возрастанием количества разнообразных расчетов и обращений к бд, будет все сложнее держать это в одном классе и тем более следить за этим барахлом, запускаемым через QtConcurrent.