Russian Qt Forum
Апрель 20, 2024, 11:03 *
Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.
Вам не пришло письмо с кодом активации?

Войти
 
  Начало   Форум  WIKI (Вики)FAQ Помощь Поиск Войти Регистрация  

Страниц: [1]   Вниз
  Печать  
Автор Тема: Многопоточность и виджеты: фундаментальный вопрос  (Прочитано 4549 раз)
PinkPanther
Самовар
**
Offline Offline

Сообщений: 169



Просмотр профиля
« : Февраль 28, 2015, 12:36 »

Добрый день. Встал фундаментальный вопрос, который не до конца понят, в силу недостаточного опыта программирования потоков.

У меня в приложении имеется QTabWidget, который, по необходимости, можно расширить некоторым количеством вкладок. Количество вкладок определяется пользователем при помощи QSpinBox, они создаются и добавляются в QTabWidget по нажатию кнопки (все сразу), а старт активности процессов на этих вкладках запускается другой кнопкой в общем окне. Потом, по необходимости, пользователь должен иметь возможность остановить процессы, удалить вкладки из QTabWidget, и начать все сначала.

На каждой вкладке есть QWebView, несколько текстовых полей (для лога, ввода URL и т.д.), и еще несколько управляющих элементов. Нужно сделать так, чтобы все виджеты вкладки, включая QWebView, работали в отдельном потоке вкладки. Также необходимо, чтобы все подключенные к виджетам слоты также работали в потоке своей вкладки.

Достаточно ли создать новый класс (например, MyTabMultiThread), унаследовав его от QTab и QThread, и добавив в него виджеты в качестве переменных?
Или виджеты, которые должны работать в потоке, необходимо создавать исключительно в функции run()?
Как насчет слотов, которые будут обслуживать события QWebView и других виджетов, принадлежащих вкладке? Как заставить слоты (а точнее, все методы дочернего класса) работать в отдельном потоке? Или следует создать для каждого типа виджеда дочерний класс, включить в него слоты обработки событий, а потом создать их экземпляры в run()? Возможно, имеет смысл создать дочерний класс лишь на базе QThread, а вкладку тоже создавать в run(), динамически, и хранить ее адрес в public-указателе дочернего класса?

Помогите пожалуйста разобраться.
« Последнее редактирование: Февраль 28, 2015, 13:07 от PinkPanther » Записан

Эвтаназия - наше хобби!
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #1 : Февраль 28, 2015, 13:26 »

Или виджеты, которые должны работать в потоке, необходимо создавать исключительно в функции run()?
Виджеты (рисование UI) могут работать только в главной нитке. Вы можете рисовать в буферах (напр QImage) но вывод на экран - только в главной. Ну и делайте выводы
Записан
PinkPanther
Самовар
**
Offline Offline

Сообщений: 169



Просмотр профиля
« Ответ #2 : Февраль 28, 2015, 13:35 »

Или виджеты, которые должны работать в потоке, необходимо создавать исключительно в функции run()?
Виджеты (рисование UI) могут работать только в главной нитке. Вы можете рисовать в буферах (напр QImage) но вывод на экран - только в главной. Ну и делайте выводы

А работа с сетью (QNetworkAccessManager)? А рендеринг HTML-страницы QWebView-ом? А код JavaScript, который выполняется на странице, а также Java и Flash?

Рисование виджетов не занимает много времени, пусть вывод на экран останется в главном потоке. А вот сетевые запросы, исполнение скриптов и рендеринг было бы желательно распараллелить.
Записан

Эвтаназия - наше хобби!
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #3 : Февраль 28, 2015, 14:27 »

Некоторые из Ваших тезисов
...создать новый класс (например, MyTabMultiThread), унаследовав его от QTab и QThread, и
...
Или виджеты, которые должны работать в потоке, необходимо создавать исключительно в функции run()?
Ну вот Вы создали виджет в "неглавной" нитке. Действия с ним вызовут события рисования которые полетят в EventLoop этой нитки. Но рисовать там нельзя - и что будете делать?

А вот сетевые запросы, исполнение скриптов и рендеринг было бы желательно распараллелить.
Так параллельте на здоровье, но без виджетов напрямую, общайтесь с ними через сигналы.
Записан
PinkPanther
Самовар
**
Offline Offline

Сообщений: 169



Просмотр профиля
« Ответ #4 : Февраль 28, 2015, 16:45 »

Ну вот Вы создали виджет в "неглавной" нитке. Действия с ним вызовут события рисования которые полетят в EventLoop этой нитки. Но рисовать там нельзя - и что будете делать?
...
Так параллельте на здоровье, но без виджетов напрямую, общайтесь с ними через сигналы.

По п.1 понял, спасибо!

По п.2... QWebView общается с сетью при помощи QNetworkAccessManager, который, в свою очередь, встроен в QWebPage. QWebPage можно заменить на свой, и QNetworkAccessManager - тоже.
Если я создам в отдельном потоке объекты этих классов и встрою в QWebView, который живет в основном потоке, будет ли такая конструкция работать?

Если будет, то сразу же старый вопрос: как организовать обработку сигналов в разных потоках? Экземпляры должны создаваться в классе, который наследует QThread, или только в ф-ции run()? Обработчики сигналов, предположительно, будут зашиты в дочерний класс. Например, обработкой окончания загрузки Url будет заниматься метод класса, наследуемого от QNetworkAccessManager.
Записан

Эвтаназия - наше хобби!
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #5 : Февраль 28, 2015, 17:13 »

Про QNetworkAccessManager ничего не скажу, с ним не работал
Экземпляры должны создаваться в классе, который наследует QThread, или только в ф-ции run()?
Не проблема, т.к. с помощью moveToThread всегда можно сказать объекту в EventLoop какой нитки он будет принимать сигналы

Если будет, то сразу же старый вопрос: как организовать обработку сигналов в разных потоках?
Так там уже все организовано Улыбающийся См Qt::AutoConnection. Пример

Object1 принадлежит QThread1 и испускает сигнал для Object2. Если Object2 в др нитке (напр QThread2), то сигнал (фактически событие) будет помещен в очередь событий QThread2. По дефаулту метод QThread2::run запускает EventLoop, значит сигнал до него дойдет. Вам остается только пулять сигналами  Улыбающийся
Записан
PinkPanther
Самовар
**
Offline Offline

Сообщений: 169



Просмотр профиля
« Ответ #6 : Февраль 28, 2015, 20:29 »

Спасибо! Очень интересно.

Я пока плохо понял, что Вы написали, т.к. не до конца понимаю, как работают многозадачные ОС, т.к. основной опыт программирования набирался в 80-90 годы, под DOS и другие однозадачные OS.

Узкое место моего приложения - обработчик окончания загрузки страницы QWebView, так как в некоторых случаях приходится вступать в сложный диалог с интерфейсом, страница которого загружается. Интерфейс содержит массу JS-кода, в JS-коде используется AJAX, он отсылает введенные программой данные на сервер сервиса, потом меняет код HTML-страницы. С момента ввода до момента изменения страницы приходится ждать, потом реагировать и принимать новые решения. И так - в цикле, до 20 раз на одну загрузку. Это случается не постоянно, но случается. Когда виджетов станет больше, загрузки будут происходить чаще, и обработка должна идти параллельно, иначе теряется смысл объединения, а если параллелить в потоке главного процесса, то начнутся тормоза.

Сейчас у меня просто запущено 5 экземпляров приложения, с одним активным браузером в каждом. Они работают, но работать с 5 приложениями неудобно. Я хочу объединить несколько QWebView, чтобы было проще вести статистику и контролировать работу. Подскажите пожалуйста, как при помощи сигналов и слотов в Qt можно вывести обработчик "страница загружена" в отдельный поток, для каждого QWebView? В каком классе он должен находиться, чтобы QWebView мог его вызывать?

Изначально я хотел поместить каждый набор виджетов в отдельный QThread, там же объявить указатели на виджеты общего статистического окна, и менять текст в главном окне, по мере необходимости. Но раз QWebView не может работать в отдельном потоке...
Записан

Эвтаназия - наше хобби!
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #7 : Март 01, 2015, 10:27 »

Сейчас у меня просто запущено 5 экземпляров приложения, с одним активным браузером в каждом. Они работают, но работать с 5 приложениями неудобно. Я хочу объединить несколько QWebView, чтобы было проще вести статистику и контролировать работу. Подскажите пожалуйста, как при помощи сигналов и слотов в Qt можно вывести обработчик "страница загружена" в отдельный поток, для каждого QWebView? В каком классе он должен находиться, чтобы QWebView мог его вызывать?
Здесь не смогу помочь т.к. с QWebView не работал. Бегло глянув букварь: ну страницу от наверняка сам грузит в отдельном потоке, по завершении выдает сигнал loadFinished. Неясно зачем Вам еще создавать поток, и что будет делать тамошний обработчик. Но еще раз: пусть ответят те кто с этим работал.


Записан
PinkPanther
Самовар
**
Offline Offline

Сообщений: 169



Просмотр профиля
« Ответ #8 : Март 01, 2015, 17:19 »

Сейчас у меня просто запущено 5 экземпляров приложения, с одним активным браузером в каждом. Они работают, но работать с 5 приложениями неудобно. Я хочу объединить несколько QWebView, чтобы было проще вести статистику и контролировать работу. Подскажите пожалуйста, как при помощи сигналов и слотов в Qt можно вывести обработчик "страница загружена" в отдельный поток, для каждого QWebView? В каком классе он должен находиться, чтобы QWebView мог его вызывать?
Здесь не смогу помочь т.к. с QWebView не работал. Бегло глянув букварь: ну страницу от наверняка сам грузит в отдельном потоке, по завершении выдает сигнал loadFinished. Неясно зачем Вам еще создавать поток, и что будет делать тамошний обработчик. Но еще раз: пусть ответят те кто с этим работал.

Не уверен, что обработка идет в отдельном потоке... Попытка повесить в окно несколько активных браузеров с обработчиками загружает приложение под завязку. Но что мешает написать обработчик, который при окончании загрузки лишь меняет переменную-флаг, а run() под каждый QWebView пасет изменение этого флага с интервалом 0.1 сек, в промежутках запуская QEventLoop? Улыбающийся
В любом случае, спасибо за разъяснения. Узнал много полезного.
Записан

Эвтаназия - наше хобби!
Страниц: [1]   Вверх
  Печать  
 
Перейти в:  


Страница сгенерирована за 0.049 секунд. Запросов: 23.