Название: Многопоточность и виджеты: фундаментальный вопрос Отправлено: PinkPanther от Февраль 28, 2015, 12:36 Добрый день. Встал фундаментальный вопрос, который не до конца понят, в силу недостаточного опыта программирования потоков.
У меня в приложении имеется QTabWidget, который, по необходимости, можно расширить некоторым количеством вкладок. Количество вкладок определяется пользователем при помощи QSpinBox, они создаются и добавляются в QTabWidget по нажатию кнопки (все сразу), а старт активности процессов на этих вкладках запускается другой кнопкой в общем окне. Потом, по необходимости, пользователь должен иметь возможность остановить процессы, удалить вкладки из QTabWidget, и начать все сначала. На каждой вкладке есть QWebView, несколько текстовых полей (для лога, ввода URL и т.д.), и еще несколько управляющих элементов. Нужно сделать так, чтобы все виджеты вкладки, включая QWebView, работали в отдельном потоке вкладки. Также необходимо, чтобы все подключенные к виджетам слоты также работали в потоке своей вкладки. Достаточно ли создать новый класс (например, MyTabMultiThread), унаследовав его от QTab и QThread, и добавив в него виджеты в качестве переменных? Или виджеты, которые должны работать в потоке, необходимо создавать исключительно в функции run()? Как насчет слотов, которые будут обслуживать события QWebView и других виджетов, принадлежащих вкладке? Как заставить слоты (а точнее, все методы дочернего класса) работать в отдельном потоке? Или следует создать для каждого типа виджеда дочерний класс, включить в него слоты обработки событий, а потом создать их экземпляры в run()? Возможно, имеет смысл создать дочерний класс лишь на базе QThread, а вкладку тоже создавать в run(), динамически, и хранить ее адрес в public-указателе дочернего класса? Помогите пожалуйста разобраться. Название: Re: Многопоточность и виджеты: фундаментальный вопрос Отправлено: Igors от Февраль 28, 2015, 13:26 Или виджеты, которые должны работать в потоке, необходимо создавать исключительно в функции run()? Виджеты (рисование UI) могут работать только в главной нитке. Вы можете рисовать в буферах (напр QImage) но вывод на экран - только в главной. Ну и делайте выводыНазвание: Re: Многопоточность и виджеты: фундаментальный вопрос Отправлено: PinkPanther от Февраль 28, 2015, 13:35 Или виджеты, которые должны работать в потоке, необходимо создавать исключительно в функции run()? Виджеты (рисование UI) могут работать только в главной нитке. Вы можете рисовать в буферах (напр QImage) но вывод на экран - только в главной. Ну и делайте выводыА работа с сетью (QNetworkAccessManager)? А рендеринг HTML-страницы QWebView-ом? А код JavaScript, который выполняется на странице, а также Java и Flash? Рисование виджетов не занимает много времени, пусть вывод на экран останется в главном потоке. А вот сетевые запросы, исполнение скриптов и рендеринг было бы желательно распараллелить. Название: Re: Многопоточность и виджеты: фундаментальный вопрос Отправлено: Igors от Февраль 28, 2015, 14:27 Некоторые из Ваших тезисов
...создать новый класс (например, MyTabMultiThread), унаследовав его от QTab и QThread, и Ну вот Вы создали виджет в "неглавной" нитке. Действия с ним вызовут события рисования которые полетят в EventLoop этой нитки. Но рисовать там нельзя - и что будете делать? ... Или виджеты, которые должны работать в потоке, необходимо создавать исключительно в функции run()? А вот сетевые запросы, исполнение скриптов и рендеринг было бы желательно распараллелить. Так параллельте на здоровье, но без виджетов напрямую, общайтесь с ними через сигналы.Название: Re: Многопоточность и виджеты: фундаментальный вопрос Отправлено: PinkPanther от Февраль 28, 2015, 16:45 Ну вот Вы создали виджет в "неглавной" нитке. Действия с ним вызовут события рисования которые полетят в EventLoop этой нитки. Но рисовать там нельзя - и что будете делать? ... Так параллельте на здоровье, но без виджетов напрямую, общайтесь с ними через сигналы. По п.1 понял, спасибо! По п.2... QWebView общается с сетью при помощи QNetworkAccessManager, который, в свою очередь, встроен в QWebPage. QWebPage можно заменить на свой, и QNetworkAccessManager - тоже. Если я создам в отдельном потоке объекты этих классов и встрою в QWebView, который живет в основном потоке, будет ли такая конструкция работать? Если будет, то сразу же старый вопрос: как организовать обработку сигналов в разных потоках? Экземпляры должны создаваться в классе, который наследует QThread, или только в ф-ции run()? Обработчики сигналов, предположительно, будут зашиты в дочерний класс. Например, обработкой окончания загрузки Url будет заниматься метод класса, наследуемого от QNetworkAccessManager. Название: Re: Многопоточность и виджеты: фундаментальный вопрос Отправлено: Igors от Февраль 28, 2015, 17:13 Про QNetworkAccessManager ничего не скажу, с ним не работал
Экземпляры должны создаваться в классе, который наследует QThread, или только в ф-ции run()? Не проблема, т.к. с помощью moveToThread всегда можно сказать объекту в EventLoop какой нитки он будет принимать сигналы Если будет, то сразу же старый вопрос: как организовать обработку сигналов в разных потоках? Так там уже все организовано :) См Qt::AutoConnection. ПримерObject1 принадлежит QThread1 и испускает сигнал для Object2. Если Object2 в др нитке (напр QThread2), то сигнал (фактически событие) будет помещен в очередь событий QThread2. По дефаулту метод QThread2::run запускает EventLoop, значит сигнал до него дойдет. Вам остается только пулять сигналами :) Название: Re: Многопоточность и виджеты: фундаментальный вопрос Отправлено: PinkPanther от Февраль 28, 2015, 20:29 Спасибо! Очень интересно.
Я пока плохо понял, что Вы написали, т.к. не до конца понимаю, как работают многозадачные ОС, т.к. основной опыт программирования набирался в 80-90 годы, под DOS и другие однозадачные OS. Узкое место моего приложения - обработчик окончания загрузки страницы QWebView, так как в некоторых случаях приходится вступать в сложный диалог с интерфейсом, страница которого загружается. Интерфейс содержит массу JS-кода, в JS-коде используется AJAX, он отсылает введенные программой данные на сервер сервиса, потом меняет код HTML-страницы. С момента ввода до момента изменения страницы приходится ждать, потом реагировать и принимать новые решения. И так - в цикле, до 20 раз на одну загрузку. Это случается не постоянно, но случается. Когда виджетов станет больше, загрузки будут происходить чаще, и обработка должна идти параллельно, иначе теряется смысл объединения, а если параллелить в потоке главного процесса, то начнутся тормоза. Сейчас у меня просто запущено 5 экземпляров приложения, с одним активным браузером в каждом. Они работают, но работать с 5 приложениями неудобно. Я хочу объединить несколько QWebView, чтобы было проще вести статистику и контролировать работу. Подскажите пожалуйста, как при помощи сигналов и слотов в Qt можно вывести обработчик "страница загружена" в отдельный поток, для каждого QWebView? В каком классе он должен находиться, чтобы QWebView мог его вызывать? Изначально я хотел поместить каждый набор виджетов в отдельный QThread, там же объявить указатели на виджеты общего статистического окна, и менять текст в главном окне, по мере необходимости. Но раз QWebView не может работать в отдельном потоке... Название: Re: Многопоточность и виджеты: фундаментальный вопрос Отправлено: Igors от Март 01, 2015, 10:27 Сейчас у меня просто запущено 5 экземпляров приложения, с одним активным браузером в каждом. Они работают, но работать с 5 приложениями неудобно. Я хочу объединить несколько QWebView, чтобы было проще вести статистику и контролировать работу. Подскажите пожалуйста, как при помощи сигналов и слотов в Qt можно вывести обработчик "страница загружена" в отдельный поток, для каждого QWebView? В каком классе он должен находиться, чтобы QWebView мог его вызывать? Здесь не смогу помочь т.к. с QWebView не работал. Бегло глянув букварь: ну страницу от наверняка сам грузит в отдельном потоке, по завершении выдает сигнал loadFinished. Неясно зачем Вам еще создавать поток, и что будет делать тамошний обработчик. Но еще раз: пусть ответят те кто с этим работал.Название: Re: Многопоточность и виджеты: фундаментальный вопрос Отправлено: PinkPanther от Март 01, 2015, 17:19 Сейчас у меня просто запущено 5 экземпляров приложения, с одним активным браузером в каждом. Они работают, но работать с 5 приложениями неудобно. Я хочу объединить несколько QWebView, чтобы было проще вести статистику и контролировать работу. Подскажите пожалуйста, как при помощи сигналов и слотов в Qt можно вывести обработчик "страница загружена" в отдельный поток, для каждого QWebView? В каком классе он должен находиться, чтобы QWebView мог его вызывать? Здесь не смогу помочь т.к. с QWebView не работал. Бегло глянув букварь: ну страницу от наверняка сам грузит в отдельном потоке, по завершении выдает сигнал loadFinished. Неясно зачем Вам еще создавать поток, и что будет делать тамошний обработчик. Но еще раз: пусть ответят те кто с этим работал.Не уверен, что обработка идет в отдельном потоке... Попытка повесить в окно несколько активных браузеров с обработчиками загружает приложение под завязку. Но что мешает написать обработчик, который при окончании загрузки лишь меняет переменную-флаг, а run() под каждый QWebView пасет изменение этого флага с интервалом 0.1 сек, в промежутках запуская QEventLoop? :) В любом случае, спасибо за разъяснения. Узнал много полезного. |