Russian Qt Forum

Qt => 2D и 3D графика => Тема начата: BiTOk от Май 03, 2010, 08:32



Название: Многопоточный вывод на QGraphicsScene
Отправлено: BiTOk от Май 03, 2010, 08:32
Доброе время суток. Пишу эмулятор прохождения по тоннелю людей. Каждый человек должен быть реализован в виде потока. Создаю несколько потоков, в них пытаюсь отрисовать человечков на QGraphicsScene, но они не рисуются и в консоль получаю вывод:
QObject::startTimer: timers cannot be started from another thread
QObject::killTimer: timers cannot be stopped from another thread
Как лучше реализовать такое, чтобы не было столь большого разделяемого ресурса и было хоть сколько-то плавное движение? Кто выводит в консоль эти сообщения?


Название: Re: Многопоточный вывод на QGraphicsScene
Отправлено: alexman от Май 03, 2010, 13:01
Рисовка возможна только в главном потоке! Например, посылай сигналы из потоков в главный поток, что требуется отрисоваться!


Название: Re: Многопоточный вывод на QGraphicsScene
Отправлено: BiTOk от Май 03, 2010, 13:04
Т.е. фактически Вы мне предлагаете реализовать очередь, куда будут кидаться запросы на различные действия, а в главном потоке эту очередь обрабатывать и отрисовывать? В каком виде реализовать это лучше: руками реализовать очередь и по таймеру её обрабатывать или какой другой механизм?


Название: Re: Многопоточный вывод на QGraphicsScene
Отправлено: lit-uriy от Май 03, 2010, 13:15
обрабатывать по мере поступления сигналов из доппотоков


Название: Re: Многопоточный вывод на QGraphicsScene
Отправлено: BiTOk от Май 03, 2010, 13:17
А как правильно реализовать саму очередь?


Название: Re: Многопоточный вывод на QGraphicsScene
Отправлено: ilyagoo от Май 03, 2010, 13:21
соединяй сигнал-слот с флагом Qt::QueuedConnection


Название: Re: Многопоточный вывод на QGraphicsScene
Отправлено: Igors от Май 03, 2010, 14:29
Т.е. фактически Вы мне предлагаете реализовать очередь, куда будут ..
Эта очередь давно имеется - eventLoop главной нитки. Все что Вам надо это из дочерних ниток посылать сигналы в главную, а там их обрабатывать/отрисовывать


Название: Re: Многопоточный вывод на QGraphicsScene
Отправлено: BiTOk от Май 05, 2010, 07:53
Сделал как Вы и сказали, сигналы отправляю главному треду. Реализовал так:
Код:
Worker::Worker(int startPlace, QObject *parent):QThread()//позиция, откуда следует начинать путь
{
    x = 25.5; //абсцисса всегда такая, ибо это сразу после начальной стены
    y = startPlace*25+25.5;

    this->parent = parent;
    myPeople = NULL;
}

void Worker::run()
{
    emit makeWorker(this, x, y);
    moveTimer = new QTimer( this );
    connect( moveTimer, SIGNAL(timeout()), this, SLOT(onTimerDown()) );
    moveTimer->start( 50 );
    qDebug("%d", this->currentThreadId());
    exec();
}

void Worker::onTimerDown()
{
    qDebug("%d onTimerDown", this->currentThreadId());
    emit moveWorker(this, myPeople);
}
Но таймер работает не в контексте нового потока, а из главного. Как правильно запустить таймер из этого потока, чтобы он срабатывал в нём же?


Название: Re: Многопоточный вывод на QGraphicsScene
Отправлено: BRE от Май 05, 2010, 08:02
Попробуй так:
Код
C++ (Qt)
void Worker::run()
{
   emit makeWorker(this, x, y);
   QTimer moveTimer;
   connect( &moveTimer, SIGNAL(timeout()), this, SLOT(onTimerDown()) );
   moveTimer.start( 50 );
   qDebug("%d", this->currentThreadId());
   exec();
}
 


Название: Re: Многопоточный вывод на QGraphicsScene
Отправлено: BiTOk от Май 05, 2010, 08:07
Попробуй так:
5840 bla
3064
5840 onTimerDown
Что означает, что таймер вновь срабатывает в контексте главного потока


Название: Re: Многопоточный вывод на QGraphicsScene
Отправлено: alexman от Май 05, 2010, 08:08
Можно попробовать sleep делать в run! То есть отказаться от таймера!


Название: Re: Многопоточный вывод на QGraphicsScene
Отправлено: BRE от Май 05, 2010, 08:12
Вместо this->currentThreadId(), попробуй писать QThread::currentThreadId()


Название: Re: Многопоточный вывод на QGraphicsScene
Отправлено: BiTOk от Май 05, 2010, 08:17
alexman
Пробовал, даёт достаточно скверный результат, ибо слип не совсем эквивалент таймеру, он даст остановку после выполнения (а выполнение может быть не быстрым), а не как таймер..
BRE
Это не принципиально, ибо данные результаты верны.


Название: Re: Многопоточный вывод на QGraphicsScene
Отправлено: Авварон от Май 05, 2010, 08:24
среди меня бытует мнение, что соединясь со слотом у объекта, созданного в главной нитке (Worker) мы таки будем выполнять этот слот в главной нитке, что вам в общем-то и надо. Создайте еще 1 объект внутри run и к неиу уже вешайте коннекты.
могу ошибаться, тк с QThread работал очень давно


Название: Re: Многопоточный вывод на QGraphicsScene
Отправлено: BiTOk от Май 05, 2010, 08:25
среди меня бытует мнение, что соединясь со слотом у объекта, созданного в главной нитке (Worker) мы таки будем выполнять этот слот в главной нитке, что вам в общем-то и надо.
могу ошибаться. тк с QThread работал очень давно
Цитировать
Qt::BlockingQueuedConnection - при генерации сигнал помещается в очередь обработки событий. Пока слот не получит сигнал текущий поток блокируется. Данный тип соединения следует применять только для получателя в другом потоке
Вообще это не так судя по всему.


Название: Re: Многопоточный вывод на QGraphicsScene
Отправлено: Авварон от Май 05, 2010, 08:32
у вас получатель в мейне. а отправитель - нет.


Название: Re: Многопоточный вывод на QGraphicsScene
Отправлено: BiTOk от Май 05, 2010, 08:39
Верно, но в этой же проге я писал, эмит сигнала в главный поток из run() и он отправлялся из run().


Название: Re: Многопоточный вывод на QGraphicsScene
Отправлено: Авварон от Май 05, 2010, 08:50
не важно откуда посылать, главное - где принимают. На то очередь и нужна, чтобы тредобезопасно перебросить из 1й нитки в другую. Я вам просто предлагаю проверить случай когда получающий не в главной нитке:) Могу ошибаться, но мне кажется такое обоснование логичным. У самого сейчас Qt далеко...


Название: Re: Многопоточный вывод на QGraphicsScene
Отправлено: BRE от Май 05, 2010, 08:59
Могу ошибаться, но мне кажется такое обоснование логичным. У самого сейчас Qt далеко...
Все верно, сразу не обратил внимания.

Нужно перетащить сам объект Worker в контекст потока:
Код
C++ (Qt)
Worker::Worker(int startPlace, QObject *parent):QThread()//позиция, откуда следует начинать путь
{
   moveToThread( this );
 
   x = 25.5; //абсцисса всегда такая, ибо это сразу после начальной стены
   y = startPlace*25+25.5;
 
   this->parent = parent;
   myPeople = NULL;
}

и все заработает.


Название: Re: Многопоточный вывод на QGraphicsScene
Отправлено: BiTOk от Май 05, 2010, 09:07
Хм.. действительно работает, спасибо, парни.


Название: Re: Многопоточный вывод на QGraphicsScene
Отправлено: alexman от Май 05, 2010, 09:16
спс, буду знать!


Название: Re: Многопоточный вывод на QGraphicsScene
Отправлено: BiTOk от Май 05, 2010, 13:54
Возник вопрос: как убить правильно поток и удалить созданный объект, если учитывать, что поток, который должен быть остановлен, накидал много-много сообщений главному треду, в одном из параметров сообщения находится указатель, который становится неверным, если прибить поток.. Если в лоб прибить - то упадёт в главном треде, а если не завершать, то будет течь память, да и вообще это как-то некрасиво. Могу выложить код, если кто захочет посмотреть.


Название: Re: Многопоточный вывод на QGraphicsScene
Отправлено: BRE от Май 05, 2010, 14:00
Возник вопрос: как убить правильно поток и удалить созданный объект, если учитывать, что поток, который должен быть остановлен, накидал много-много сообщений главному треду, в одном из параметров сообщения находится указатель, который становится неверным, если прибить поток.. Если в лоб прибить - то упадёт в главном треде, а если не завершать, то будет течь память, да и вообще это как-то некрасиво. Могу выложить код, если кто захочет посмотреть.
В твоем случае, т.к. используется цикл обработки событий:
Код
C++ (Qt)
thread->quit(); // Говорим - завершиться
thread->wait(); // Ждем пока завершиться
// Делай с указателем, что хочешь
 

или

Код
C++ (Qt)
connect( thread, SIGNAL( finished() ), thread, SLOT( deleteLater() ) );
 


Название: Re: Многопоточный вывод на QGraphicsScene
Отправлено: BiTOk от Май 05, 2010, 14:50
Но bool QThread::finished () const, разве это можно использовать в качестве сигнала?


Название: Re: Многопоточный вывод на QGraphicsScene
Отправлено: BRE от Май 05, 2010, 14:56
Но bool QThread::finished () const, разве это можно использовать в качестве сигнала?
Найди два отличия:  :)
bool QThread::isFinished () const
void QThread::finished ()   [signal]