QGraphicsView / Scene - многопоточный кошмар - PullRequest
0 голосов
/ 26 ноября 2009

Правильно ли я считаю, что классы QGraphics * не являются поточно-ориентированными? Я портирую старое приложение на Qt и пытаюсь сделать его многопоточным. Я посмотрел на код обновления и не вижу никаких блокировок.

Я начал правильно, вся моя обработка выполняется в виде набора рабочих потоков, поэтому графический интерфейс не должен блокироваться. Но как только я прихожу, чтобы показать свое визуальное представление, все падает, как колода карт, когда код обновления пытается прочитать из буфера, в который пишет другой поток.

Вот мой тестовый пример:

  1. Создание группы объектов эллипса
  2. Создать поток и передать ему указатель на сцену
  3. В цикле измените любую настройку для любого объекта в сцене.

Функция тестирования:

bool CBasicDocument::Update( float fTimeStep )
{
const QList<QGraphicsItem*> tObjects = items();

for( QList<QGraphicsItem*>::const_iterator tIter = tObjects.constBegin();
tIter != tObjects.constEnd();
++tIter )
 {
    QGraphicsEllipseItem* pElipse = (QGraphicsEllipseItem*)(*tIter);
   if( pElipse )
   {   
      pElipse->setPen( QPen( QColor( (int)(255.0f * sinf( fTimeStep )), (int)(255.0f * cosf( fTimeStep )), (int)(255.0f * sinf( fTimeStep )) ) ) );
   }
 }
return true;
}

Я думал о том, как я могу это исправить, и ни один из них не особенно хорош.

В идеале я хочу, чтобы я изменил настройку объекта, он буферизировался до следующего вызова рендеринга, но пока я согласен, что он не потерпит крах!

На данный момент у меня есть четыре варианта:

  1. Двойная буферизация всей сцены с сохранением двух графов сцен в одном шаге (один рендеринг, одно обновление). Так работает наш многопоточный игровой движок. Здесь это ужасно, потому что это потребует удвоения процессорного времени и удвоения памяти. Не говоря уже о логистике ведения обоих графов сцен.

  2. Измените QGraphics *, чтобы обеспечить безопасность потоков, как указано выше. Вероятно, это наиболее практичный подход, но для его выполнения потребуется много работы.

  3. Вставить изменения в сцену в очередь и обработать их из основного потока.

  4. Сбросьте многопоточность на время и просто позвольте моему приложению зависнуть при обновлении документа. (Не очень, учитывая размер данных для некоторых документов)

Ни один из них не особенно привлекателен и требует огромного количества работы.

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

Приветствия

Ответы [ 2 ]

2 голосов
/ 26 ноября 2009

Я всегда читал, что лучше, чтобы вся работа с графическим интерфейсом выполнялась в главном потоке, независимо от того, используете ли вы GTK, Qt или другое.

В вашем случае я бы выбрал вариант 2.

Изменение кода Qt для установки здесь блокировок, и в ihmo самое худшее, что вы можете сделать, так как вы не сможете синхронизировать ваш модифицированный Qt с апстримом без значительного объема работы.

0 голосов
/ 26 ноября 2009

В вашей тестовой функции я заметил, что вы уже приводите (используя приведения в стиле c) QGraphicsItem к QGraphicsEllipseItem. Если вы используете только определенное количество типов элементов, может быть проще создать подклассы этих типов и обеспечить поточно-ориентированные функции в этих подклассах. Затем приведите к этим подклассам и назовите то, что вы хотите, из другого потока. Они могут обрабатывать буферизацию изменений, блокировку мьютекса или все, что вы хотите сделать для этих изменений.

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...