Russian Qt Forum

Qt => Общие вопросы => Тема начата: skydion от Март 12, 2010, 10:39



Название: Завершение QThread
Отправлено: skydion от Март 12, 2010, 10:39
Собственно вопрос, как правильно прекращать работу треда...?
У меня запускается тред на сканирование файлов, ну все это дело долгое,
поэтому нужно из интерфейса завершать тред, сейчас делал просто

Код:
bool MainWindow::stopScan()
{
if (thread)
{
thread->terminate();
thread->wait(500);
qDebug("Thread terminated");

delete thread;
}
}

почитал про треды и там есть предупреждение

]void QThread::terminate ()
Warning: This function is dangerous and its use is discouraged.



Название: Re: Завершение QThread
Отправлено: hackoff от Март 12, 2010, 11:05
thread->exit(0);
thread->deleteLater();


Название: Re: Завершение QThread
Отправлено: skydion от Март 12, 2010, 11:14
я так понимаю Вашим кодом заменить этот код?

thread->terminate();
thread->wait(500);

а как проверить завершился ли поток?
чтобы сделать изменения в интерфейсе? разблокировать заблокировать кнопки?
раньше я делал через перехват сигнала terminated (), а теперь finished () ловить?


Название: Re: Завершение QThread
Отправлено: skydion от Март 12, 2010, 12:26
теперь вот така фигня вылазит...

QObject::killTimers: timers cannot be stopped from another thread чем лечить?

Код:
MainWindow::MainWindow
{
    thread = new ScanThread(this);
}

void MainWindow::scanVocabulary(void)
{
    if (thread)
    {
thread->start(QThread::NormalPriority);

ui->pushButtonStart->setDisabled(true);
ui->pushButtonStop->setDisabled(false);

qDebug("scanVocabulary: Scan thread started");
    }
}

void MainWindow::stopScan()
{
    if (thread)
    {
thread->exit(0);
thread->deleteLater();

ui->pushButtonStart->setDisabled(false);
ui->pushButtonStart->setChecked(false);
    }
}

ScanThread::~ScanThread()
{
    if (!isRunning())
return;

    if (text.count())
    {
drv->beginTransaction();
query.addBindValue(text);
query.execBatch(QSqlQuery::ValuesAsRows);

le = query.lastError();
if (le.type() == QSqlError::NoError)
   drv->commitTransaction();
else
   qDebug() << "~ScanThread: [" << le.text() << "]";

query.finish();
    }

    wait(500);
}


Название: Re: Завершение QThread
Отправлено: alexman от Март 12, 2010, 12:38
Замени
Код:
thread->exit(0);
thread->deleteLater();
на
Код:
thread->wait();
delete thread;


Название: Re: Завершение QThread
Отправлено: alexman от Март 12, 2010, 12:54
Кстати,
Код:
void MainWindow::stopScan()
{
    if (thread)
    {
thread->exit(0);
thread->deleteLater();

ui->pushButtonStart->setDisabled(false);
ui->pushButtonStart->setChecked(false);
    }
}
к этому моменту поток уже знает, что ему нужно завершиться? Если нет, то перед этим ему нужно отправить сигнал, чтобы он завершился.


Название: Re: Завершение QThread
Отправлено: skydion от Март 12, 2010, 13:25
Замени
Код:
thread->exit(0);
thread->deleteLater();
на
Код:
thread->wait();
delete thread;

вначале у меня так было... смотри начало треда...


Название: Re: Завершение QThread
Отправлено: skydion от Март 12, 2010, 13:28
Кстати,
к этому моменту поток уже знает, что ему нужно завершиться? Если нет, то перед этим ему нужно отправить сигнал, чтобы он завершился.

как он может знать? какой сигнал ему послать?
я его хочу принудительно остановить, притом корректно (мне еще при завершении треда надо буфер скинуть в БД)


Название: Re: Завершение QThread
Отправлено: alexman от Март 12, 2010, 13:40
Из потока нельзя принудительно завершать другой поток!
terminate() -> Warning: This function is dangerous and its use is discouraged. The thread can be terminate at any point in its code path. Threads can be terminated while modifying data. There is no chance for the thread to cleanup after itself, unlock any held mutexes, etc. In short, use this function only if absolutely necessary.

Тебе нужно как-нибудь уведомить о завершении другой поток из главного; например, послать сигнал canceled(), по сигналу сделать cancel = true, а далее
Цитировать
void run ()
{
    while(...) {
    ...
        if ( cancel ) {
            return;
        }
    ...
    }
}


Название: Re: Завершение QThread
Отправлено: alexman от Март 12, 2010, 13:42
Ну а далее в главном потоке уже можно вызвать
Цитировать
thread->wait();
delete thread;


Название: Re: Завершение QThread
Отправлено: Igors от Март 12, 2010, 13:43
как он может знать? какой сигнал ему послать?
я его хочу принудительно остановить, притом корректно (мне еще при завершении треда надо буфер скинуть в БД)
Принудительно не надо - можно нарваться на неприятности. Нитка завершится когда она выйдет из своего метода run - Вам надо каким-то образом сказать ей когда выходить. Напр. если нитка крутит EventLoop, сделайте ей quit. Если нитка занимается чисто расчетами - сделайте ей флажок типа FlagStop и проверяйте его в расчетах. После этого цивильно ждите завершения: thread->wait(); а можно и подсесть на сигнал нитки terminated()


Название: Re: Завершение QThread
Отправлено: skydion от Март 12, 2010, 13:51
спасибо Вам, щас все осмыслю и буду ваять, много инфы навалилось  ;D


Название: Re: Завершение QThread
Отправлено: ieroglif от Март 12, 2010, 13:57
Код:
ThreadClass * thrd = new ThreadClass();
connect(thrd ,SIGNAL(finished()),thrd ,SLOT(deleteLater()));
thrd->start();
ну а внутри треда держать переменную булевскую и создать слот по её изменению.


Название: Re: Завершение QThread
Отправлено: skydion от Март 12, 2010, 16:26
Всем спасибо, все решилось положительно :)


Название: Re: Завершение QThread
Отправлено: Djavdet от Апрель 13, 2010, 13:49
как конкретно?