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

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

Страниц: 1 2 3 [4] 5   Вниз
  Печать  
Автор Тема: Тестовое задание на программиста С++/Qt компания некстерс  (Прочитано 46596 раз)
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #45 : Сентябрь 05, 2016, 11:45 »

В том то и дело, что подготовку данных для финального отображения (где учитывается и порядок, и много чего еще - эффекты, текстуры и т.п.) можно совершенно параллельно, да и обрабатывать события GUI и др. можно независимо от финальной процедуры отображения. Улыбающийся И формально только реализованная в Qt стратегия обработки событий накладывает ограничения на принадлежность всего дерева Widget одному и тому же потоку.
Думаю "собственно рисованием" занимается обработчик события UpdateRequest. Это он вызывает paintEvent рекурсивно. Начиная с пятерки рисуется все в QImage (хотя это противоречит double-buffer). В конце обработчик вызывает нативный API для вывода на экран.

ОС посылает событие рисования (что выливается в UpdateRequest) в той нитке где создано QApplication (обычно главной). Просто вызвать UpdateRequest из др нитки может и можно (не проверял), но эффекта не имеет т.к. нет dirtyRegions - нужен сначала update, а он вызовет рисование в главной.
Записан
GreatSnake
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2921



Просмотр профиля
« Ответ #46 : Сентябрь 05, 2016, 12:40 »

Помимо рисования есть ещё так называемый "focus-manager", который занимается рассылкой клавиатурных событий непосредственно виджетам.
Если кто не знает, то все клавиатурные события от системы приходят в top-level окно и уже непосредственно тулкит занимается их управлением.
Так вот всё это управление тоже далается в обработчике событий gui-потока.
Записан

Qt 5.11/4.8.7 (X11/Win)
ssoft
Программист
*****
Offline Offline

Сообщений: 579


Просмотр профиля
« Ответ #47 : Сентябрь 05, 2016, 13:20 »

Да ничего она не накладывает. Можно рисовать хоть все виджеты сцены, каждый в своем потоке, правда рисовать придется в буфер (QImage). А вот окончательное рисование придется выполнять в paintEvent. Вот как раз метод paintEvent и вызывает тот самый, кто-знает порядок отрасивки всех виджетов и без кторого нормально сцену не построить.

Это только один из возможных методов), нативно реализованный в Qt. Но внутри paintEvent можно только готовить данные для отрисовки кадра (менять атрибуты графических узлов сцены, готовить QImage, или вообще напрямую заполнять массивы в видеопамяти), а непосредственно отображением может заниматься отдельная сущность в отдельном потоке, совершенно никак не связанная ни с QWidget, ни с Qt. Порядок отрисовки зависит только от порядка графических узлов сцены, а частота кадров может никак и не зависеть от частоты вызовов paintEvent.

Вопрос был другой - Почему GUI в Qt всегда однопоточный. Сам процесс отображения не накладывает никаких ограничений на многопоточность GUI, а вот обеспечение правильного порядка обработки событий клавиатуры или мыши можно легко достигнуть с помощью ограничения однопоточности, да и за голыми указателями не нужно следить, и signal/slot в виде Direct соединений, и множество других небрежных плюшек. Изначально GUI было спроектировано таким образом, а далее ...

Цитировать
А так как менять эту систему - значит переписать очень много много кода и ещё больше сил потратить на поддержку устаревших программ, то это никому не надо. Так и живём  Веселый

Это ограничение так сильно пронизывает Qt, что устранять его не целесообразно. Проще написать другой инструментарий.
Записан
Racheengel
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2679


Я работал с дискетам 5.25 :(


Просмотр профиля
« Ответ #48 : Сентябрь 05, 2016, 14:19 »

Я другого не понимаю - а зачем вам всем так многопоточный гуй сдался? Улыбающийся
Разве что для второго монитора?
Рисовать в буфер и сейчас можно и в потоках, а потом в главном гуе собирать картинку.
Какие будут преимущества иметь много гуепотоков Непонимающий
Записан

What is the 11 in the C++11? It’s the number of feet they glued to C++ trying to obtain a better octopus.

COVID не волк, в лес не уйдёт
Old
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 4349



Просмотр профиля
« Ответ #49 : Сентябрь 05, 2016, 14:24 »

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

совершенно никак не связанная ни с QWidget, ни с Qt.
И что получиться: венда/XWindow/...?
Большим достоинством Qt является то, что она может самостоятельно все отрисовать внутри некой области/top-level окна.
Записан
Old
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 4349



Просмотр профиля
« Ответ #50 : Сентябрь 05, 2016, 14:26 »

Я другого не понимаю - а зачем вам всем так многопоточный гуй сдался? Улыбающийся
Я бы вообще с удовольствием послушал четкую формулировку "многопоточного гуя". Улыбающийся
Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #51 : Сентябрь 05, 2016, 14:37 »

Я другого не понимаю - а зачем вам всем так многопоточный гуй сдался? Улыбающийся
Да, применение ограничено, но есть. Не всегда удается вынести трудоемкую операцию в поток чтобы оставить UI свободным. В этом случае хорошо бы рисовать индикатор из "не UI" нитки. В этом году обсуждали.
Записан
ssoft
Программист
*****
Offline Offline

Сообщений: 579


Просмотр профиля
« Ответ #52 : Сентябрь 05, 2016, 15:30 »

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

Не могли Троли вызывать paintEvent "и в отдельной нитке" Улыбающийся, так как это привело бы к необходимости синхронизации внутренностей QWidget и производных классов. В этом и отличие отдельной независимой сущности отображения и сущности вызывающей paintEvent.

Цитировать
Я бы вообще с удовольствием послушал четкую формулировку "многопоточного гуя". Улыбающийся

Здесь как раз все просто). GUI является частным случаем отображением чего-либо. Отображение может складываться из данных разной природы - разные источники данных, разные виды отображаемой информации и т.д. Иногда, целесообразно для данных разной природы иметь независимые друг от друга сущности, управляющие их отображением и реагирующие на события изменения данных (подгрузка, пересчет, уточнение деталлизации данных) или GUI события. Когда отображаемых элементов боольшое количество, а требуемое время отклика достаточно мало, многопоточность становится весьма актуальной.
Записан
ssoft
Программист
*****
Offline Offline

Сообщений: 579


Просмотр профиля
« Ответ #53 : Сентябрь 05, 2016, 15:53 »

Такой пример. Предположим необходимо отобразить два независимых GUI для управления устройством 1 и устройством 2 в одном. Существует также требование, что изменение состояние устройств должно быть отображено не позднее, чем 100 мс. При выполнении операции после нажатия на кнопку устройства 1 происходит подготовка данных порядка нескольких секунд. Что делать в однопоточной реализации GUI?

Естественное решение - формировать дополнительный поток (с соответствующими накладными расходами), обеспечивающий подготовку данных, или как-то использовать processEvents(). В многопоточном GUI в этом нет необходимости, так как отображение и реакция на события уже многопоточны (асинхронны).
Записан
Old
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 4349



Просмотр профиля
« Ответ #54 : Сентябрь 05, 2016, 16:08 »

Не могли Троли вызывать paintEvent "и в отдельной нитке" Улыбающийся, так как это привело бы к необходимости синхронизации внутренностей QWidget и производных классов.
Могли. Нужно было синхронизировать только доступ к теневому буферу виджета.

В этом и отличие отдельной независимой сущности отображения и сущности вызывающей paintEvent.
Нет никаких отличий. paintEvent это синоним получения теневого буфера окна. Он необходим для любого варианта отображения.

Здесь как раз все просто). GUI является частным случаем отображением чего-либо. Отображение может складываться из данных разной природы - разные источники данных, разные виды отображаемой информации и т.д. Иногда, целесообразно для данных разной природы иметь независимые друг от друга сущности, управляющие их отображением и реагирующие на события изменения данных (подгрузка, пересчет, уточнение деталлизации данных) или GUI события. Когда отображаемых элементов боольшое количество, а требуемое время отклика достаточно мало, многопоточность становится весьма актуальной.
Можно готовить теневые буферы хоть в 100500 потоках, конечное отображение всегда будет однопоточным. Не могут окна конкурировать друг с другом, каша будет получаться.
Записан
Old
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 4349



Просмотр профиля
« Ответ #55 : Сентябрь 05, 2016, 16:14 »

Естественное решение - формировать дополнительный поток (с соответствующими накладными расходами), обеспечивающий подготовку данных, или как-то использовать processEvents(). В многопоточном GUI в этом нет необходимости, так как отображение и реакция на события уже многопоточны (асинхронны).
Окна устройства 1 и устройства 2 могут перекрываться, как они будут обновляться на экране?
Окно устройства 1 обновляется 1 раз в 100 мс, окно устройства 2 обновляется 1 раз в 5 сек. Окно устройства 2 перекрывает на половину окно устройства 1. Как будет обновляться видимая часть окна устройства 1? Кто будет это контролировать?
Записан
ssoft
Программист
*****
Offline Offline

Сообщений: 579


Просмотр профиля
« Ответ #56 : Сентябрь 05, 2016, 16:54 »

Окна устройства 1 и устройства 2 могут перекрываться, как они будут обновляться на экране?
Окно устройства 1 обновляется 1 раз в 100 мс, окно устройства 2 обновляется 1 раз в 5 сек. Окно устройства 2 перекрывает на половину окно устройства 1. Как будет обновляться видимая часть окна устройства 1? Кто будет это контролировать?

Да, вполне могут и перекрываться). Кадр или его часть, формируется отдельной сущностью (Renderer), которая оперирует графом графических примитивов. GUI устройств асинхронно оперируют с узлами данного графа, добавляя/изменяя/удаляя их. Renderer в соответствии с этим графом может обновлять кадр по таймеру, или по изменению графа или еще как-то, асинхронно относительно GUI. Порядок рисования кадра определяется графом примитивов, а не каждым GUI устройств отдельно. При этом подготовка кадра Renderer'ом может быть многопроходной и многопоточной (конкурентной) при необходимости.

Асинхронный (многопоточный) GUI не означает независимую друг от друга и конкурирующую отрисовку, а означает независимую обработку событий и управление отображаемыми примитивами. Когда операции одного GUI не блокируют любой другой.
« Последнее редактирование: Сентябрь 05, 2016, 17:06 от ssoft » Записан
Old
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 4349



Просмотр профиля
« Ответ #57 : Сентябрь 05, 2016, 17:14 »

Кадр или его часть, формируется отдельной сущностью (Renderer)
Так вот этот самый рендерер и есть та самая сущность, которая однопоточно все отрисовывает. Про нее я вам и речь веду.
Если вы все отрисовки виджетов будете делать в других потоках на QImage, а в paintEvent просто рисовать полученный QImage на виджет, у вас получиться тот самый способ отрисовки, в котором Qt будет в роли рендерера.
Записан
ssoft
Программист
*****
Offline Offline

Сообщений: 579


Просмотр профиля
« Ответ #58 : Сентябрь 05, 2016, 17:43 »

Так вот этот самый рендерер и есть та самая сущность, которая однопоточно все отрисовывает. Про нее я вам и речь веду.

Так это я давно понял  Смеющийся. Просто многопоточный GUI (о чем собственно разговор) и способ отображения - разные вещи. Многопоточный GUI подразумевает независимую реакцию элементов GUI на события, без явных взаимных блокировок друг друга и рендерера. А уж каким способом происходит формирование кадра (граф, набор QImage или др.) это уже дело конкретной реализации рендерера. При этом рендерер сам по себе может быть и многопоточный, те же QImage можно совмещать и параллельно для разных ветвей иерархии.

PS: Да, и нарямую вызывать метод paintEvent чревато, так как GUI элемент может быть и удален ненароком в момент вызова, отображаем то асинхронно. Лучше уж QImage держать независимо от GUI в отдельном дереве рендерера.
Записан
Old
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 4349



Просмотр профиля
« Ответ #59 : Сентябрь 05, 2016, 20:04 »

При этом рендерер сам по себе может быть и многопоточный, те же QImage можно совмещать и параллельно для разных ветвей иерархии.
Нет. Если элементы ветвей могут перекрываться - не может. А именно про это идет речь. Qt изначально умел рисовать все сам в frame buffer (что являлось его огромным плюсом), поэтому он сам является тем оконным композитором, который должен все отобразить. А это, для перекрывающихся виджетов, можно сделать только в один поток.

PS: Да, и нарямую вызывать метод paintEvent чревато, так как GUI элемент может быть и удален ненароком в момент вызова, отображаем то асинхронно. Лучше уж QImage держать независимо от GUI в отдельном дереве рендерера.
Когда вызывается paintEvent уже никто удалиться не может, потому что он может вызывается только из того самого рендерера, который должен быть в конечном итоге однопоточным. И именно он хранит иерархию отображаемых объектов.

Многопоточный GUI подразумевает независимую реакцию элементов GUI на события, без явных взаимных блокировок друг друга и рендерера.
Ok, с отображением вопросы отпали, остались с реакцией. Улыбающийся
А что в Qt принципиально не позволяет сделать независимую реакцию элементов?
« Последнее редактирование: Сентябрь 05, 2016, 21:46 от Old » Записан
Страниц: 1 2 3 [4] 5   Вверх
  Печать  
 
Перейти в:  


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