Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > С/С++: Кроссплатформенное программирование, Qt/Gtk+/wxWidgets > [Qt] как и где удалять объект после moveToThread


Автор: maric2000 14.12.2012, 08:25
У меня вопрос о принадлежности объектов потока.
Информацию о "Хорошем способе" проектирования работы с потоком почерпнул отсюда http://habrahabr.ru/post/115835/ . 

Пример из статьи:
class Worker : public QObject
{
    Q_OBJECT
 
public slots:
    void doWork() {
        /* ... */
    }
}; 
/* ... */
QThread thread;
Worker worker;
connect(obj, SIGNAL(workReady()), &worker, SLOT(doWork()));
worker.moveToThread(&thread);
thread.start();

Объект который должен выполнятся в потоке, мы отправляем выполнятся в поток методом moveToThread.
Вопрос такой: кому принадлежит и где удаляется объект Worker после worker.moveToThread(&thread)?

Если объект Worker создается динамически
Worker *worker = new Worker;
connect(obj, SIGNAL(workReady()), worker, SLOT(doWork()));
worker->moveToThread(&thread);
thread.start();
, то где и как его потом удалять?

Автор: bsa 14.12.2012, 10:52
maric2000, делай умный указатель и храни его где-нибудь так, чтобы он уничтожился раньше, чем поток.

Автор: maric2000 14.12.2012, 13:25
Цитата(bsa @  14.12.2012,  10:52 Найти цитируемый пост)
maric2000, делай умный указатель и храни его где-нибудь так, чтобы он уничтожился раньше, чем поток. 

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

Видимо все же проще унаследовать QThread, и в его методе run() создавать объект Worker. Тогда и проблем с удалением Worker не возникает.
Просто в статье утверждалось что первый вариант лучше.

Автор: borisbn 14.12.2012, 15:33
Цитата(maric2000 @  14.12.2012,  13:25 Найти цитируемый пост)
Просто в деструкторе MainWindow нужно средствами синхронизации сперва завершить Worker, затем поток.

Код
connect( worker, SIGNAL( onFinish() ), & thread, SLOT( quit() ) );
worker->finishWork();
thread.wait();
delete worker;


нет ?

Автор: maric2000 17.12.2012, 06:35
Спасибо, вроде  то что нужно.
Только смущает вызов worker->finishWork(), т.к. это прямой вызов ф-ии из другого потока.

Может вызов этой ф-ии заменить на :

connect( this, SIGNAL( signalFinishWork() ), & worker, SLOT( finishWork() ) );
emit signalFinishWork();

?

Добавлено через 12 минут и 41 секунду
опечатка в предыдущем посте:
Код

connect( this, SIGNAL( signalFinishWork() ), worker, SLOT( finishWork() ) );

Автор: maric2000 17.12.2012, 08:41
И все же непонятно что происходит с динамическим объектом после вызова moveToThread (worker->moveToThread(&thread);). А интересно узнать.
Родителем остается MainWindow, но выполняется он в потоке thread, поэтому вызывать его функции из MainWindow нельзя (без средств сихронизации). Или как?
Данный вопрос не освещен ни в документации Qt, ни в учебниках по Qt. По крайней мере я не нашел.

Добавлено через 3 минуты и 1 секунду
Поправлюсь: MainWindow не является родителем, просто в его конструкторе создается worker 

Автор: bsa 17.12.2012, 11:18
maric2000, когда ты создаешь объект наследник QObject, то все операции с сигналами и слотами ассоциируются с создающим потоком. Но ты хочешь, чтобы объект работал в другом потоке. Для этого, необходимо произвести переассоциацию, что и делает moveToThread. 

Автор: maric2000 17.12.2012, 12:23
Что вы имеете ввиду под переассоциацией?

Добавлено через 9 минут и 14 секунд
То, что "объект обрабатывает события, которые попадают в цикл обработки событий, того потока, которому принадлежит" я уже понял.

Автор: maric2000 17.12.2012, 12:48
Т.е. moveToThread меняет принадлежность к потоку объекта и после завершения потока его необходимо удалить (если объект был создан динамически) или не использовать (если объект - стековый). А все правильно понял? 

Автор: bsa 17.12.2012, 13:35
Цитата(maric2000 @  17.12.2012,  13:48 Найти цитируемый пост)
после завершения потока его необходимо удалить (если объект был создан динамически) или не использовать (если объект - стековый). А все правильно понял?  
Да. Ну еще можно сделать moveToThread на незавершившийся поток.

Автор: maric2000 17.12.2012, 14:12
Спасибо! Все ясно.
Т.е. после завершения потока, в котором выполнялся worker, единственно доступной функцией по отношению к нему остается delete?
Можно ли в finishWork() объкта worker вызывать deleteLater(), чтобы не писать delete worker в основном потоке?

Цитата(bsa @  17.12.2012,  13:35 Найти цитируемый пост)
Ну еще можно сделать moveToThread на незавершившийся поток

Например в finishWork() вызвать moveToThread(QApplication::instance()->thread()) чтоб вернуть объект обратно? 

Автор: bsa 17.12.2012, 16:17
maric2000, а кто запрещает?

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)