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

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

Страниц: [1] 2 3   Вниз
  Печать  
Автор Тема: suggestion  (Прочитано 39973 раз)
Авварон
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 3260


Просмотр профиля
« : Март 07, 2011, 01:22 »

Давно не лазил на форуме, заглянул в этот раздел и ужаснулся. Почему все поголовно используют moveToThread(this); Непонимающий Это же неправильно. Может прикрепить тему с линкой на блог, к-ую я уже задолбался кидать, почему это неверно и как надо писать?
Записан
merke
Гость
« Ответ #1 : Март 07, 2011, 05:35 »

Я к примеру использую
Код:
thread->moveToThread(thread);
Записан
Sahab
Гость
« Ответ #2 : Март 07, 2011, 11:42 »

давай раскроешь эту тему более полнее.
Записан
Авварон
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 3260


Просмотр профиля
« Ответ #3 : Март 07, 2011, 13:34 »

который раз кидаю линк:)
http://labs.qt.nokia.com/2010/06/17/youre-doing-it-wrong/

В кратце содержание:
В доке кьюта есть ошибка касательно примера с кьютредом - они его сабклассят. Эта "ошибка" существует еще с тех пор, когда у QThread не было дефолт имплементации метода run() (который ныне содержит вызов exec()). Собсно об этом был другой блог (http://labs.qt.nokia.com/2006/12/04/threading-without-the-headache/) - можно ли заменить pure virtual ф-ию на virtual без слома бинари совместимости. Можно. Итого имеем - метод run() вызывает exec(), а в примере делается сабклассинг и о5 же делается exec() для сигналов/слотов.
Почему неверно сабклассить - наследование нужно для расширения функционала самого класса. Мы расширяем кьютред? Нет. Мы добавляем функционал, к-й в общем случае к самому объекту тред не имеет отношения. Посему нужно использовать аггрегацию. Начал расписывать словами, понял, что кодом проще:
Код:
class Worker : public QObject
{
    Q_OBJECT
public slots:
    void work();
signals:
    void finished();
};

void Worker::work()
{
    // do some work
    emit finished();
}

int main()
{
    QThread thread;
    Worker w;
    w.moveToThread(&thread);
    QObject::connect(&thread, SIGNAL(started()), &w, SLOT(work()));
    QObject::connect(&w, SIGNAL(finished()), &thread, SLOT(quit()));
    thread.start();
}

Плюсы этого метода - можно делать много объектов в 1м треде, как и много экземпляров 1го класса в разных тредах. Ну и никакого сабклассинга - наш класс содержит _только_ нашу логику и не пересекается с тредом. Ну и еще нет взрыва мозга новичкам зачем тред переносить в себя (да, так можно писать, но надо четко понимать что и зачем а не рандомить "без му ту тред не работало, написал мэджик строку, заработало")

Вольный перевод окончен:)
Можете пинать.
« Последнее редактирование: Март 07, 2011, 13:36 от Авварон » Записан
Авварон
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 3260


Просмотр профиля
« Ответ #4 : Март 07, 2011, 13:50 »

Гы, кстати по 2й линке пример еще и зависание должен вызвать. Коннект-то директ будет, тк треды еще не назначены.
(или кьют поменяет тип авто коннекта при муве? О_о)
Записан
Akon
Гость
« Ответ #5 : Март 07, 2011, 14:07 »

moveToThread() иногда используется для сокетов входящих соединений, для "выема" сокета из исходного потока слушающего сокета.

А так все по делу, конечно.
Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #6 : Март 07, 2011, 14:19 »

Гы, кстати по 2й линке пример еще и зависание должен вызвать. Коннект-то директ будет, тк треды еще не назначены.
(или кьют поменяет тип авто коннекта при муве? О_о)
auto "расшифровывается" в момент посылки сигнала, поэтому зависания не будет.
Насчет "субклассить" - как правило все равно придется, т.к. "(приватные) данные этой нитки" нужны очень часто (если не всегда).

А вообще Ваше желание обобщить мне симпатично. Вот др. вещь с которой я сталкивался: Qt использует "fair" мутекс (т.е. который "честно" усыпляет нитку - на базе pthread_cond_wait). Это может быть катастрофически медленно во многих случаях и разумной альтернативы в Qt не видно (поправьте если не так)
« Последнее редактирование: Март 07, 2011, 14:21 от Igors » Записан
Авварон
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 3260


Просмотр профиля
« Ответ #7 : Март 07, 2011, 15:41 »

Гы, кстати по 2й линке пример еще и зависание должен вызвать. Коннект-то директ будет, тк треды еще не назначены.
(или кьют поменяет тип авто коннекта при муве? О_о)
auto "расшифровывается" в момент посылки сигнала, поэтому зависания не будет.
Насчет "субклассить" - как правило все равно придется, т.к. "(приватные) данные этой нитки" нужны очень часто (если не всегда).

А вообще Ваше желание обобщить мне симпатично. Вот др. вещь с которой я сталкивался: Qt использует "fair" мутекс (т.е. который "честно" усыпляет нитку - на базе pthread_cond_wait). Это может быть катастрофически медленно во многих случаях и разумной альтернативы в Qt не видно (поправьте если не так)

Ну насчет данных нитки можно поспорить:) Когда как.

Насчет мьютекса - если честно не знаю, мне обычно треды нужны были "чтоб гуй не зависал" - то есть некая работа, скорость к-ой особо не нужна, посему не заморачивался - ставил мьютексы, работало:) Скорость не профилировал.

moveToThread() иногда используется для сокетов входящих соединений, для "выема" сокета из исходного потока слушающего сокета.

А так все по делу, конечно.
Ну никто не говорит, что moveToThread не нужен. Не нужно саму нитку перемещать в ее контекст.
Записан
Sahab
Гость
« Ответ #8 : Март 07, 2011, 22:35 »

Цитировать
moveToThread() иногда используется для сокетов входящих соединений, для "выема" сокета из исходного потока слушающего сокета.

Цитировать
void QTcpServer::incomingConnection ( int socketDescriptor ) [virtual protected]
...
Note: If you want to handle an incoming connection as a new QTcpSocket object in another thread you have to pass the socketDescriptor to the other thread and create the QTcpSocket object there and use its setSocketDescriptor() method.
Записан
Sahab
Гость
« Ответ #9 : Март 08, 2011, 00:30 »

2 Авварон
а Вы попробуйте в Вашем примере добавить в Worker тот же таймер.
Записан
Авварон
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 3260


Просмотр профиля
« Ответ #10 : Март 10, 2011, 11:48 »

а в чем проблема? надо только старт дергать из потока же ж, не?
Записан
vunder
Гость
« Ответ #11 : Март 11, 2011, 10:47 »

Мои некоторые заметки по поводу this->moveToThread(this)
Я использую эту строку, потому как без нее мой код работает "криво".
Немного описания. Мне нужен был класс, который бы из TCP-потока читал xml-данные и парсил из. Сокет создавался через new QTCPSocket(this), потому как это только базовый класс, 2 его потомка по-разному создаею сокеты: первый коннектится по адресу, второй использует SocketDescriptior. Кроме того, указатель на сокет нужен, т.к. в базовом классе есть общие методы по отправке данных по сокету.
Более того, без this->moveToThread(this) у меня не срабатывает сигнал error(QAbstractSocket::SocketError):
Цитировать
QObject::connect: Cannot queue arguments of type 'QAbstractSocket::SocketError'
(Make sure 'QAbstractSocket::SocketError' is registered using qRegisterMetaType().)
Эту проблему я решил добавлением строки
Код
C++ (Qt)
   qRegisterMetaType<QAbstractSocket::SocketError>("QAbstractSocket::SocketError");
Но посыпались проблемы с таймером. Я использую startTimer() и killTimer(). Вызываются они в методе run(), т.е. в контексте потока (о чем свидетельствовала отладочная информация в QtCreator на закладке "Потоке", а также qDebug() << this->currentThreadId()). Однако, событие timerEvent(QTimerEvent *event) срабатывало в контексте главного процесса.
Также я заметил, что и слоты, которые я повесил на сокет, также срабатывают в контексте главного потока.
Также, в методе run() создается и сам сокет:
Код
C++ (Qt)
   fSocket = new QTcpSocket(this);
Однако, на это я получаю ошибку
Цитировать
QObject: Cannot create children for a parent that is in a different thread.
(Parent is UnpClientProtocol(0x12d5cd0), parent's thread is QThread(0x10ebd40), current thread is UnpClientProtocol(0x12d5cd0)
Т.е. предок объекта (QThread) находится в другом потоке, поэтому так нельзя.

Вот такие вот "пироги".
Записан
Авварон
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 3260


Просмотр профиля
« Ответ #12 : Март 11, 2011, 16:17 »

сам таймер пробовали перемещать в другой тред?
Записан
vunder
Гость
« Ответ #13 : Март 12, 2011, 12:56 »

сам таймер пробовали перемещать в другой тред?
Что значит в "другой"? Я использую методы startTimer() и killTimer(), которые есть у каждого наследника QObject
Записан
Авварон
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 3260


Просмотр профиля
« Ответ #14 : Март 14, 2011, 08:13 »

Ставлю 10 р что встроенный таймер тоже проверяет тред в к-ом работает. Попробуйте таки сделать мув ту тред. Ну и бтв мой пример _ничем_ не отличается от способа работы когда наследуешься от треда - ровно те же объекты будут перенесены в тред. Иногда имеет смысл делать слот init() к-ый надо дергать в контексте треда и там создавать нужны объекты.
Записан
Страниц: [1] 2 3   Вверх
  Печать  
 
Перейти в:  


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