Russian Qt Forum

Qt => Общие вопросы => Тема начата: serg_hd от Апрель 23, 2010, 15:48



Название: [решено] Как зачистить QObject из другого потока?
Отправлено: serg_hd от Апрель 23, 2010, 15:48
Не могу его никак удалить.
Есть дочерний поток класса-наследника QThread и пара дополнительных методов:
Код
C++ (Qt)
void MyClass::run()
{
this->signalMapper = new QSignalMapper();
...
this->addNewTimer();
}
 
void MyClass::addNewTimer()
{
QTimer* timer = new QTimer();
QObject::connect(timer, SIGNAL(timeout()), this->signalMapper, SLOT(map()));
this->signalMapper->setMapping(timer, timer);
}
 

Далее маппер соединён со слотом delTimer(), чтобы при timeout() каждого таймера вызывался именно он:

Код
C++ (Qt)
void myClass::delTimer(QObject* timer)
{
// timer->moveToThread(this);
// timer->setParent(0);
// timer->moveToThread(this->thread());
// delete timer;
}
 

Пробовалось всё что закомментировано и не только это, но остальное посчитал лишним.
Ошибка: QObject::killTimer: timers cannot be stopped from another thread
Вот, хотелось бы узнать как удалить этот timer...


Название: Re: Как зачистить QObject из другого потока?
Отправлено: Kolobok от Апрель 23, 2010, 15:55
А deleteLater не подходит?


Название: Re: Как зачистить QObject из другого потока?
Отправлено: serg_hd от Апрель 23, 2010, 16:03
если
Код
C++ (Qt)
void myClass::delTimer(QObject* timer)
{
qDebug() << "text";
timer->deleteLater();
}
 
то текст действительно выводится только 1 раз, т.е. таймер сигнала больше не испускает. Но:
1) немного непонятен смысл - когда именно он удалится, ведь память выделялась вручную, не хотелось бы никакой утечки.
2) а если бы хотел удалить "нормальным" способом, то как?


Название: Re: Как зачистить QObject из другого потока?
Отправлено: SABROG от Апрель 23, 2010, 16:13
1) немного непонятен смысл - когда именно он удалится, ведь память выделялась вручную, не хотелось бы никакой утечки.
Как только управление вернется в цикл событий, обычно это происходит после возврата из метода в котором вызвал deleteLater().

2) а если бы хотел удалить "нормальным" способом, то как?
После moveToThread() объект невозможно вернуть обратно в поток, где он создавался. Поэтому и удалять надо в том потоке в который его переместили. А если не перемещали, то в том потоке, где создавали.


Название: Re: Как зачистить QObject из другого потока?
Отправлено: serg_hd от Апрель 23, 2010, 16:22
в том-то и дело, что если:
Код
C++ (Qt)
void myClass::delTimer(QObject* timer)
{
timer->moveToThread(this);
delete timer;
}
 

то будет ошибка: "QObject::killTimer: timers cannot be stopped from another thread".
А если
Код
C++ (Qt)
void myClass::delTimer(QObject* timer)
{
timer->moveToThread(this->thread());
delete timer;
}
 

то "QObject::moveToThread: Current thread (0x11680898) is not the object's thread (0x3d6a68). Cannot move to target thread (0x3d6a68)".
timer->setParent(0); ситуацию не меняет. Интересно всё-таки, наверняка когда-нибудь придётся удалять через delete.


Название: Re: Как зачистить QObject из другого потока?
Отправлено: BRE от Апрель 23, 2010, 16:29
В том месте, где делаешь соединение со слотом void MyClass::addNewTimer() задай тип подключения Qt::QueuedConnection.
Или ты его только из run вызываешь?


Название: Re: Как зачистить QObject из другого потока?
Отправлено: serg_hd от Апрель 23, 2010, 16:34
В том месте, где делаешь соединение со слотом void MyClass::addNewTimer() задай тип подключения Qt::QueuedConnection.
Или ты его только из run вызываешь?

Да, слотом является только delTimer.


Название: Re: Как зачистить QObject из другого потока?
Отправлено: SABROG от Апрель 23, 2010, 16:35
Код
C++ (Qt)
this->addNewTimer();
 

У тебя таймер создается в отдельном потоке, зачем ему делать moveToThread?


Название: Re: Как зачистить QObject из другого потока?
Отправлено: serg_hd от Апрель 23, 2010, 16:37
Код
C++ (Qt)
this->addNewTimer();
 

У тебя таймер создается в отдельном потоке, зачем ему делать moveToThread?
потому что удаляется он уже в другом. И неужто я бы сначала не попробовал удалить его без перемещения? :)


Название: Re: Как зачистить QObject из другого потока?
Отправлено: Kolobok от Апрель 23, 2010, 16:39
У таймера какая задача? Себя уничтожить?


Название: Re: Как зачистить QObject из другого потока?
Отправлено: serg_hd от Апрель 23, 2010, 16:41
У таймера какая задача? Себя уничтожить?
нет, это у слота для маппера такая задача - уничтожать таймер когда тот испускает таймаут. Естественно реальная задача другая, тут вынес очень урезанный код, чтобы людей не путать. Но смысл остался.


Название: Re: Как зачистить QObject из другого потока?
Отправлено: SABROG от Апрель 23, 2010, 16:46
С таймерами между потоками совсем другая история нежели с обычным QObject'ом. Сомневаюсь, что тут moveToThread() поможет. Как бы троллям не пришлось писать, чтобы запретили перенос таймеров между потоками.


Название: Re: Как зачистить QObject из другого потока?
Отправлено: BRE от Апрель 23, 2010, 16:46
Т.е. код можно упростить так:
Код
C++ (Qt)
void MyClass::run()
{
this->signalMapper = new QSignalMapper();
...
QTimer* timer = new QTimer();
QObject::connect(timer, SIGNAL(timeout()), this->signalMapper, SLOT(map()));
this->signalMapper->setMapping(timer, timer);
}
 

Правильно?

Если да, то удалять таймер нужно через deleteLater, т.к. сам таймер является инициатором этого сигнала и используется подключение Qt::DirectConnection.
Никаких moveToThread не нужно, все и так в одном потоке создается.


Название: Re: Как зачистить QObject из другого потока?
Отправлено: Kolobok от Апрель 23, 2010, 16:49
В том слоте, который вызывается, нужен этот таймер?


Название: Re: Как зачистить QObject из другого потока?
Отправлено: serg_hd от Апрель 23, 2010, 16:51
Т.е. код можно упростить так:
Код
C++ (Qt)
void MyClass::run()
{
this->signalMapper = new QSignalMapper();
...
QTimer* timer = new QTimer();
QObject::connect(timer, SIGNAL(timeout()), this->signalMapper, SLOT(map()));
this->signalMapper->setMapping(timer, timer);
}
 
Правильно?
Да, так и есть. Но я решил вынести в отдельный метод, т.к. в ране было бы слишком много кода (в реальности картина по объёмнее), но суть та же.


Название: Re: Как зачистить QObject из другого потока?
Отправлено: serg_hd от Апрель 23, 2010, 16:52
С таймерами между потоками совсем другая история нежели с обычным QObject'ом. Сомневаюсь, что тут moveToThread() поможет. Как бы троллям не пришлось писать, чтобы запретили перенос таймеров между потоками.
понятно. Учтёмс.


Название: [решено] Как зачистить QObject из другого потока?
Отправлено: serg_hd от Апрель 23, 2010, 16:53
В том слоте, который вызывается, нужен этот таймер?
да, к таймеру привязана инфа (через property()), поэтому идёт работа с этими данными. И удаление таймера как реакция на одно из условий.
В любом случае удалю тогда через deleteLater(), спасибо за совет, как-то забыл за него совсем.


Название: Re: [решено] Как зачистить QObject из другого потока?
Отправлено: serg_hd от Апрель 23, 2010, 17:49
как бы ещё в этом слоте setInterval() для таймера вызывать, чтобы установить ему новый интервал, было бы совсем хорошо.


Название: Re: [решено] Как зачистить QObject из другого потока?
Отправлено: Kolobok от Апрель 23, 2010, 19:12
QMetaObject::invokeMethod + QTimer::start ( int msec ) ?