2009-10-12 2 views
-1

Следующий код потока работает 2058 раз, после чего он сбой. Может ли кто-нибудь помочь мне понять, почему? Идея программы - создать некоторый класс в основном потоке, передать его рабочему потоку, потоку заполнить необходимые данные и передать данные обратно в основной поток. Этот пример сработает после 2058 прогонов, однако он должен идти неопределенно. Я запустил его 20 раз, всегда столько же. В версии уменьшенных вызовов qWarning() (печатать простые строки каждые 100 запусков) поток получает 3000 раз. Поэтому я думаю, что это не зависит от количества вызовов qWarning(). И почему адрес указателя для SharedData * d всегда один и тот же?Вопросы QThread. Сбой после 2058 прогонов

main.cpp

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

    TestThread* thread = new TestThread(); 

    MainWindow w(thread); 
    w.show(); 

    delete thread; 
    return a.exec(); 
} 

mainwindow.h

#ifndef MAINWINDOW_H 
#define MAINWINDOW_H 

#include <QtGui/QMainWindow> 
#include <QThread> 
#include <QHash> 

class SharedData 
{ 
    public: 
     SharedData(); 
     QString var; 
     QHash<QString, QString> hash; 
}; 

class TestThread : public QThread 
{ 
    Q_OBJECT 

    public: 
     TestThread(QObject *parent = 0); 
     void doWork(SharedData* _data); 
     void doCrash(QHash<QString, QString>* hash); 
    signals: 
     void completed(SharedData* d); 
    private: 
     SharedData* data; 
    protected: 
     void run(); 
}; 

namespace Ui 
{ 
    class MainWindow; 
} 

class MainWindow : public QMainWindow 
{ 
    Q_OBJECT 

public: 
    MainWindow(TestThread* t, QWidget *parent = 0); 
    ~MainWindow(); 
    void runThread(); 
public slots: 
    void jobDone(SharedData* req); 

private: 
    Ui::MainWindow *ui; 
    TestThread* t; 
    int runcount; 
}; 

#endif // MAINWINDOW_H 

mainwindow.cpp

#include "mainwindow.h" 
#include "ui_mainwindow.h" 
#include <QDebug.h> 

TestThread::TestThread(QObject *parent) : QThread(parent) 
{ 
} 

void TestThread::run() 
{ 
    qWarning() << "Thread running"; 
    data->var = "hello"; 
    doCrash(&data->hash); 
    emit completed(data); 
} 

void TestThread::doWork(SharedData* _data) 
{ 
    data = _data; 
    qWarning() << "Attempting to start"; 
    if(!isRunning()) 
    { 
     run(); 
    } 
    else 
    { 
     qWarning() << "Oops. Already running"; 
    } 
} 

void TestThread::doCrash(QHash<QString, QString>* hash) 
{ 
    hash->insert("test", "123"); 

    /* 
    QHashIterator<QString, QString> i(*hash); 
    while (i.hasNext()) { 
     i.next(); 
     qWarning() << i.key() + ":" + i.value(); 
    } 
    */ 
} 

SharedData::SharedData() 
{ 
} 

void MainWindow::jobDone(SharedData* req) 
{ 
    qWarning() << "RETURNED"; 
    qWarning() << "var: " << req->var << " addr: " << &req->var; 
    qWarning() << "cnt: " << req->hash.count() << " addr: " << &req->hash; 

    QHashIterator<QString, QString> i(req->hash); 

    while (i.hasNext()) { 
     i.next(); 
     qWarning() << i.key() + ":" + i.value(); 
    } 

    delete req; 
    runThread(); 
} 

MainWindow::MainWindow(TestThread* _t, QWidget *parent) 
    : QMainWindow(parent), ui(new Ui::MainWindow) 
{ 
    ui->setupUi(this); 

    t = _t; 
    connect(t, SIGNAL(completed(SharedData*)), this, SLOT(jobDone(SharedData*))); 
    runcount = 0; 
    runThread(); 
} 

void MainWindow::runThread() 
{ 
    SharedData* d = new SharedData(); 
    d->var = "test"; 

    runcount++; 
    qWarning() << "Run count: " << runcount; 

    qWarning() << "CREATING THREAD"; 
    qWarning() << "var: " << d->var << " addr: " << &d->var; 
    qWarning() << "cnt: " << d->hash.count() << " addr: " << &d->hash; 

    t->doWork(d); 
} 

MainWindow::~MainWindow() 
{ 
    delete ui; 
} 
+0

Что говорит журнал аварий? –

ответ

2

Вы не должны удалить экземпляр TestThread в main.cpp (закомментировать " delete thread; "string)!

+1

Это правильно. Вы запускаете вещи в удаленном потоке, что всегда приведет к неопределенному поведению. Чтобы правильно исправить ситуацию, вы должны объявить целое число, чтобы сохранить результат a.exec(), а затем удалить поток, а затем вернуть целое число. –

+0

Нет, если вы удалите вызов для удаления, то ошибка. Я пробовал это на втором компьютере. – Pavels

2

Как указано в vnm, причиной сбоя является, скорее всего, инструкция delete thread; в main.cpp: при вызове w.show() он немедленно вернется, это вызов exec(), который запустится цикл и блок событий, но к тому времени уже слишком поздно, когда поток уже удален.

Я бы объявил поток как не указательный элемент основного окна вместо передачи его в качестве параметра, таким образом, компилятор выполнит очистку и инициализацию для вас. Еще более простым решением было бы использовать QtConcurrent::run. Делая это, вы устраните все явные коды протектора, но все равно получите преимущества многопоточности.

+0

Нет, удаление было ошибкой, но все равно происходит сбой перед операцией delete. – Pavels

+0

Это, вероятно, состояние гонки. Попробуйте подход QtConcurrent, он должен сделать ваш код намного чище, и, возможно, вы сможете обнаружить ошибку. – rpg