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


Автор: null56 17.3.2009, 22:16
В общем столкнулся со следующей проблемой, приведу упрощенный код (cpp):

Код

class thread : public QThread
{
public:
    thread();
    ~thread();

protected:
    void run();
};


Код

thread::thread()
{
}
thread :: ~thread()
{
    qDebug("wait thread: %d", QThread :: currentThread());
    terminate();
    qDebug("after terminate thread: %d", QThread :: currentThread());
    wait();
    qDebug("wait thread: %d", QThread :: currentThread());
}

void thread :: run()
{
    qDebug("thread: %d", QThread :: currentThread());
}

Собственно чего хочу добиться, чтобы перед удалением объекта Thread, дочерний поток (или функция run()) завершалась, а основной поток и в принципе это работает в большинстве случаев, но иногда все застревает на функции wait();
Код

main thread: 6540096
thread: 664888560
wait thread: 6540096
after terminate thread: 6540096
ВИСИМ!!!

Хотел поинтересоваться, возможен ли такой способ гарантированного завершения дочернего потока перед уничтожением самого объекта QThread или нет?
Для меня критична задача завершения этой функции, не важно в какой точке, за собой все почистят стековые объекты внутри функции run()...
Почему зависание происходит именно в точке wait? проблема в коде или в том, что я слишком часто запускаю подряд эту прогу, что какой - нибудь глобальный ресурс не освобождается, но это конечно маловероятно?
Или же такие вещи делать в деструкторе нельзя? хотя сама переменная локальная и тоже удаляется внутри функции, по идее отрабатывать должно

Заранее благодарен за помощь

Автор: pan2004 17.3.2009, 22:45
Цитата(null56 @  17.3.2009,  22:16 Найти цитируемый пост)
за собой все почистят стековые объекты внутри функции run()..

сомнительно, имхо:
Цитата

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.

Вообще, эта функция довольно опасна, и лучше по возможности обойтись без нее(например, устанавливать при выходе флаг завершения потока, который периодически проверять в run()).

Автор: null56 17.3.2009, 23:38
я делал изначально без нее, пытаясь завершить eventloop внутри потока, так там все упиралось в то, что вызов завершения обработчика событий quit() проихоил после того, как запускался сам exec() и потом все зависало на том же wait, так как из exec() уже выйти было никак... что - то типа такого было...
Код

Thread :: ~Thread()
{
      quit();
      wait();
}

Thread :: run()
{
      MyEventLoop event_loop;
      event_loop.exec();
      // в деструкторе моего обработчика событий происходила необходимая мне очистка
}


Вышеприведенный код, судя по отладочной печати запускал евент луп между вызовом quit и wait(); но опять ж не всегда.... 
Кто - нибудь придумывал способы, которые бы тормозили основной поток до того момента пока не запускался бы поток или в случае разрушения,  останавливался???

Автор: Acer 18.3.2009, 00:29
Все, что находится не в методе
Код

public:
        void run();

запускается в родительском(главном) потоке. Все, что в методе
Код

public:
        void run();

запускается в дочернем потоке.
Код

thread :: ~thread()
{
    qDebug("wait thread: %d", QThread :: currentThread());
    terminate(); /* перемести это в метод run() , если нужно убить дочерний поток */
    qDebug("after terminate thread: %d", QThread :: currentThread());

    wait(); /*вот тут ты "вешаешь" основной поток*/

    qDebug("wait thread: %d", QThread :: currentThread());
}

Автор: null56 18.3.2009, 00:46
Код

 terminate(); /* перемести это в метод run() , если нужно убить дочерний поток */

А разьве не для того этот метод, чтобы как раз аварийно выйти из функции run, если верить тебе, что убить дочерний поток вообще нельзя из родительского?

ну вот смотри, допустим фрагмент кода из мейна
Код

Thread thread;
thread.start();
thread.terminate();
thread.wait();

Разьве это аналогично тому, что я делал в деструкторе класса Thread?

Автор: Acer 18.3.2009, 01:16
Возможно, я не правильно понял проблему.

Добавлено через 7 минут и 3 секунды
Смотри, если делать так, как ты писал
Код

thread::thread()
{
}
thread :: ~thread()
{
    qDebug("wait thread: %d", QThread :: currentThread());
    terminate();
    qDebug("after terminate thread: %d", QThread :: currentThread());
    wait();
    qDebug("wait thread: %d", QThread :: currentThread());
}
void thread :: run()
{
    qDebug("thread: %d", QThread :: currentThread());
}

Тут же завершается поток до того, как будет вызван деструктор. Так? То есть звершать уже нечего. И terminate() просто не сработает. А вот wait() повесит основной поток на ULONG_MAX, то есть на бесконечность.
Цитата

time milliseconds has elapsed. If time is ULONG_MAX (the default), then the wait will never timeout (the thread must return from run()). This function will return false if the wait timed out.


Добавлено через 14 минут и 16 секунд
Только что поробовал так же сделать... Через раз зависает...
Цитата

d:\xCPR\TestQt\debug>TestQt.exe
not terminated
return
destructor
//нормально отработало
d:\xCPR\TestQt\debug>TestQt.exe
not terminated
return
^C  //завис
d:\xCPR\TestQt\debug>TestQt.exe
not terminated
return
thread
^C //завис
d:\xCPR\TestQt\debug>
d:\xCPR\TestQt\debug>TestQt.exe
not terminated
return
destructor
//нормально отработало
d:\xCPR\TestQt\debug>TestQt.exe
not terminated
return
destructor
//нормально отработало
d:\xCPR\TestQt\debug>

вот с таким кодом:
Код

class thread: public QThread {
public:
    thread(){
    };
    ~thread(){
        terminate();
        qDebug() << "destructor";
        wait();
    };
public:
    void run(){
//        for ( long i = 0; i < 1000000000; i++ ){
        qDebug() << "thread";
//        }
    };
};

int main(int argc, char *argv[]){
    QApplication app( argc, argv );
    thread t;
    t.start();
    //system( "pause" );
    //t.terminate();
    if ( !t.isRunning() ){
        qDebug() << "terminated";
    } else {
        qDebug() << "not terminated";
    }
    qDebug() << "return";
    return 0;
}

Автор: Acer 18.3.2009, 01:39
Нашел кое-что. http://lists.trolltech.com/qt-interest/2008-02/thread00572-0.html
Пишут, что если в собственном деструкторе убивать поток, то ничего не произойдет.

Автор: null56 18.3.2009, 10:02
Да, похоже на то....
А нет стандартных средств заставить родительский поток ждать пока дочерний поток не запустится?
все бы намного упростилось...

Автор: null56 18.3.2009, 13:21
Сделал в start()
Код

        QThread :: start();
    while (!isRunning())
        { QThread::sleep(1); }


а в деструкторе
Код

    quit();
    wait();


Хорошее ли решение? хотя вероятность того, что поток стартует, но не успеет войти в eventloop до того, как в деструкторе будет вызван quit, но войдет в wait(), конечно остается, но вероятность мала....

Добавлено через 10 минут и 23 секунды
в деструкторе поправил
Код

{ quit(); } while (!wait(250))

Не очень красиво, но зато наверняка наверное?

Автор: Vaulter 18.3.2009, 15:34
буду писАть на коленке
Код

thread::run() {

    obj1 = new Object();

    while ( !this->alarm ) {
           // ...doing somthg


           ///....
    }


    delete obj1;

}

thread::~thread()        {

    this->alarm = true;
    wait();// здесь мы должны подождать столько времени, 
// чтобы хватило хотя бы на одну итерацию цикла while в run()


.....
}


Автор: null56 18.3.2009, 16:01
ну да, суть ясна, спасибо...

Просто у меня все на eventloop завязано

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