Russian Qt Forum

Qt => Многопоточное программирование, процессы => Тема начата: Примерный ученик от Декабрь 19, 2010, 15:24



Название: Не убивается поток Qt3.3.8 VC2005
Отправлено: Примерный ученик от Декабрь 19, 2010, 15:24
В потоке идут сложные вычисления, которые могут цыклить.
Если поток долго не заканчивается, то его нужно убить.
Решение принимает оператор.
При попытке убить
 
Код:
terminate()
в отладчике получаю сообщение
Код:
Non-recursive mutex already locked by this thread

Как его все таки убить?


Название: Re: Не убивается поток Qt3.3.8 VC2005
Отправлено: Fat-Zer от Декабрь 19, 2010, 17:16
В документации пишут, что 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.

Предложение: заводите булевскую переменную и при необходимате останова ставите её в тру, в цикле проверяете значение.

ЗЫ: это по опыту работы c qt4, с 3-им не работал


Название: Re: Не убивается поток Qt3.3.8 VC2005
Отправлено: Примерный ученик от Декабрь 19, 2010, 17:24
Нет там цикла. Однократный вызов функции, написанной сторонним разработчиком.
Если данные не корректны, то функция может вычислять до конца веков...
Проверить данные заранее нет возможности... ???


Название: Re: Не убивается поток Qt3.3.8 VC2005
Отправлено: Fat-Zer от Декабрь 19, 2010, 17:56
ругань идёт на QMutex, а если его просто объявить объявить рекурсивным?


Название: Re: Не убивается поток Qt3.3.8 VC2005
Отправлено: Примерный ученик от Декабрь 19, 2010, 17:59
Поскольку вычисление однократное, я мютекс вообще не использовал ???


Название: Re: Не убивается поток Qt3.3.8 VC2005
Отправлено: Fat-Zer от Декабрь 19, 2010, 18:05
А можно код связанный с потоком?


Название: Re: Не убивается поток Qt3.3.8 VC2005
Отправлено: Примерный ученик от Декабрь 19, 2010, 18:47
тело исполнения

Код:
void parVF::run()
{
               double obr=0.0, vit=0.0,tz=0.0,kz=0;
calc( &obr, &tz, &vit, &kz);
if ( kz == 0 )
{
T = obr;
H = tz;
L =vit;
}
}
// выдача результата расчета
QApplication::postEvent( rc, new THL_Message(T,H,L) );
}


Название: Re: Не убивается поток Qt3.3.8 VC2005
Отправлено: Примерный ученик от Декабрь 20, 2010, 11:03
Неужели нельзя убить процесс???
 ???


Название: Re: Не убивается поток Qt3.3.8 VC2005
Отправлено: Fat-Zer от Декабрь 20, 2010, 11:48
в коде вроде ничего криминального...
ещё из документации:
Цитировать
This function terminates the execution of the thread. The thread may or may not be terminated immediately, depending on the operating system's scheduling policies. Use QThread::wait() after terminate() for synchronous termination.

Ещё на всякий случай выложите запуск, останов и объявление потока


Название: Re: Не убивается поток Qt3.3.8 VC2005
Отправлено: Примерный ученик от Декабрь 20, 2010, 12:49
Код:
		parVF = new parV(this,F0);
if (parVF)
{
parVF->start();
                }

Код:
	if (parVF)
{
parVF->terminate();
if (parVF->finished())
{
delete (parVF);
parVF=0;
}
}

Предполагается многократное использование расчета.


Название: Re: Не убивается поток Qt3.3.8 VC2005
Отправлено: Fat-Zer от Декабрь 20, 2010, 14:02
Вроде тоже ничего страшного.
А как в документации посоветовали:
Код:
parVF->terminate();
parVF->wait();
Не помогает?


Название: Re: Не убивается поток Qt3.3.8 VC2005
Отправлено: Примерный ученик от Декабрь 20, 2010, 14:09
пробовал...
Не помогает...
Висит зараза и все тут ???
поток этот грузит процессор на 99%.
Может еще попробовать узнавать ID потока и убивать системными средствами?
Но как то коряво будет ::)


Название: Re: Не убивается поток Qt3.3.8 VC2005
Отправлено: Fat-Zer от Декабрь 20, 2010, 14:26
Висит зараза и все тут ???
поток этот грузит процессор на 99%.
Это ожидаемо было...
а если вместо реальных вычислений заглушку впихнуть, while(1);?


Название: Re: Не убивается поток Qt3.3.8 VC2005
Отправлено: Примерный ученик от Декабрь 20, 2010, 14:59
Эффект тот же
Код:
Non-recursive mutex already locked by this thread


Название: Re: Не убивается поток Qt3.3.8 VC2005
Отправлено: Fat-Zer от Декабрь 20, 2010, 16:14
теряюсь в догадках, что делать... видимо во время бесперерывного выполнения нельзя убить...
Код:
while(1) usleуp(1);
При такой заглушке завершение должно пройти нормально...
В 4.4 появилась вкусная штука QFuture, её можно было бы попробовать... что с 3-им делать - хз


Название: Re: Не убивается поток Qt3.3.8 VC2005
Отправлено: Примерный ученик от Декабрь 20, 2010, 17:49
Попробовал
Код:
parVF->exit()
Приложение валится, а процесс как ни в чем ни бывало фурычит и дальше ???


Название: Re: Не убивается поток Qt3.3.8 VC2005
Отправлено: sadhu от Декабрь 20, 2010, 20:24
3 Qt остался на работе, но в 4 имееться дополнительная "защита от дурака", дабы получить возможность убивать нити методом terminate надо в любом месте программы вызвать защищённый статический метод
void setTerminationEnabled ( bool enabled = true ).
Если в 3 аналога нет , то завтра если не запамятую гляну , т.к как раз похожую ситуацию мне и предстоит в ближайшем будующем реализовать :)


Название: Re: Не убивается поток Qt3.3.8 VC2005
Отправлено: Fat-Zer от Декабрь 20, 2010, 20:29
нет, в 3-их такой защиты нет... в 4-х даже после вызова этого метода поток постоянно выполняющийся не убивается...


Название: Re: Не убивается поток Qt3.3.8 VC2005
Отправлено: sadhu от Декабрь 20, 2010, 21:13
В третьих пока могу посмотреть только документацию, кстати возможно стоит просто дождаться когда процесс прерветься ( QThread::wait() ) ибо "The thread may or may not be terminated immediately, depending on the operating system's scheduling policies." .

Что имееться в виду под
в 4-х даже после вызова этого метода поток постоянно выполняющийся не убивается...

Спецом проверил ща и убиваеться в любом случае и при
Код:
...
TestThread::run()
{
while(true){полезная_нагрузка_дабы_не_убило_оптимизацией;}
}
...
и при
Код:
...
TestThread::run()
{
полезная_нагрузка;
exec();
}
...


Название: Re: Не убивается поток Qt3.3.8 VC2005
Отправлено: Fat-Zer от Декабрь 20, 2010, 21:42
О_о я тоже только сегодня днём пробовал...
Не убивается, мой пример:

Код:
// widget.h
#ifndef WIDGET_H
#define WIDGET_H

#include <QWidget>
#include <QThread>

class Thread: public QThread
{
public:
Thread()
{
setTerminationEnabled(1);
}

void run()
{
int i;
while(1) i++;
}

};

class Widget : public QWidget
{
Q_OBJECT
public:
explicit Widget(QWidget *parent = 0);
public slots:
void terminateThread();
private:
Thread *thr;
};

#endif // WIDGET_H


// widget.cpp
#include <QPushButton>
#include "widget.h"

Widget::Widget(QWidget *parent)
:QWidget(parent)
{
QPushButton *btn=new QPushButton(this);
thr = new Thread();
thr->start();
connect(btn,SIGNAL(clicked()),
this,SLOT(terminateThread()));
}

void Widget::terminateThread()
{
thr->terminate();
thr->wait();
}



// main.cpp
#include <QApplication>
#include "widget.h"

int main(int argc, char *argv[])
{
QApplication a(argc, argv);

Widget w;
w.show();
return a.exec();
}

Тоже самое, если setTerminationEnabled(1) ставить где-либо ещё...


Название: Re: Не убивается поток Qt3.3.8 VC2005
Отправлено: Примерный ученик от Декабрь 21, 2010, 10:19
Самое неприятное, что метод
Код:
Qt::HANDLE currentThread () 
возвращает код GUI-потока. ???
Так что и системными средствами не убить зависший поток >:(


Название: Re: Не убивается поток Qt3.3.8 VC2005
Отправлено: Примерный ученик от Декабрь 21, 2010, 10:44
Пробовал ставить минимальный приоритет...
Не помогает ???
Как жрал 99%, так стал 96% жрать и все ;D


Название: Re: Не убивается поток Qt3.3.8 VC2005
Отправлено: brankovic от Декабрь 21, 2010, 15:59
С qthread не знаю что, но сама постановка нехорошая:

Проблема

1. допустим таки убили вы тред. В результате утечка памяти (в момент postMessage). Кроме того, убивание malloc в середине вызова может привести вообще к падению или завису malloc в другом треде. Зачем вам такая программа?

Варианты решения

2. вставить в calc проверку флага, по которому тред культурно выходит (предлагали уже выше). Пусть написано другим разработчиком, если код доступен, вставьте флаг. Это простой путь.

3. можно запустить calc в отдельном процессе. Не знаю, насколько просто ipc в кьют, но принципиально это возможно. Это долгий путь. Но устойчивость получится выше.


Название: Re: Не убивается поток Qt3.3.8 VC2005
Отправлено: Waryable от Декабрь 22, 2010, 09:32
Согласен с последним автором. Убиение потока "топором" - это всегда не хорошо. В данном случае полагаться на то, что система разрулит то, что вы не смогли разрулить своим кодом не безопасно. Тем более, что ввести флаг, разрешающий/запрещающий дальнейшую работу, довольно просто.


Название: Re: Не убивается поток Qt3.3.8 VC2005
Отправлено: Примерный ученик от Декабрь 22, 2010, 15:01
Нет у меня доступа к исходному коду модуля вычислений...
При его убиении я ничего не теряю


Название: Re: Не убивается поток Qt3.3.8 VC2005
Отправлено: brankovic от Декабрь 22, 2010, 15:38
Если доступа действительно нет, то единственный надёжный вариант -- запустить в отдельном процессе. В документации есть некий QProcess, например. На вид то, что нужно.

При его убиении я ничего не теряю

Что значит, "я ничего не теряю"? Вот микрософт нам пишет:

http://msdn.microsoft.com/en-us/library/ms686717%28v=vs.85%29.aspx
 (http://msdn.microsoft.com/en-us/library/ms686717%28v=vs.85%29.aspx)

суть:

Цитировать
TerminateThread is used to cause a thread to exit. When this occurs, the target thread has no chance to execute any user-mode code. DLLs attached to the thread are not notified that the thread is terminating. The system frees the thread's initial stack.

    Windows Server 2003 and Windows XP/2000:  The target thread's initial stack is not freed, causing a resource leak.

TerminateThread is a dangerous function that should only be used in the most extreme cases. You should call TerminateThread only if you know exactly what the target thread is doing, and you control all of the code that the target thread could possibly be running at the time of the termination. For example, TerminateThread can result in the following problems:

    * If the target thread owns a critical section, the critical section will not be released.
    * If the target thread is allocating memory from the heap, the heap lock will not be released.
    * If the target thread is executing certain kernel32 calls when it is terminated, the kernel32 state for the thread's process could be inconsistent.
    * If the target thread is manipulating the global state of a shared DLL, the state of the DLL could be destroyed, affecting other users of the DLL.

Обратите внимание на замечание про 2003/2000/XP, память будет течь независимо от вашего кода или от реализации calc.

Даже если течь не смущает или платформа другая, всё равно. Не имея кода calc, как вы можете быть уверены, что там не вызывается malloc? Один прерванный malloc, это на 99% либо падение, либо зависание в _любом_ треде! С таким же успехом "оператор" может снимать программу на ctrl-alt-del и запускаться заново.

Итого: причина, по которой QThread::terminate не работает под windows в том, что terminate там вообще не нужен. Но тот же метод вполне безопасно реализован в linux и, возможно, ещё на каких-то платформах, только поэтому он продолжает существовать.