Как безопасно завершать объекты, запущенные в разных потоках в QT - PullRequest
2 голосов
/ 04 марта 2012

Я учусь запускать объекты в разных потоках.Я начал с этого простого упражнения, чтобы запускать объекты в разных потоках и общаться между ними.Теперь у меня проблемы с завершением программы.Как безопасно уничтожить объекты, запущенные в разных потоках при выходе из системы?Если я ставлю ожидание потоков перед main для завершения потоков, программа зависает при wait ().Если я не ставлю ожидание, потоки никогда не выполняются, и потоки немедленно удаляются как основные выходы.

    --------testthread.h------------------
    #ifndef TESTTHREAD_H
    #define TESTTHREAD_H

   #include <QThread>
   #include <QApplication>
   #include <string>
   #include <iostream>

   using namespace std;
   class testThread : public QObject
   {
     Q_OBJECT
     public:
     testThread(const string&, QThread*);
    ~testThread();
private:
    QThread* thread;
    string _threadName;
signals:
    void requestCalculateSquare(int);
public slots:
    void calculateSquare(int);
    void start();

  };

   #endif // TESTTHREAD_H}

   -----testthread.cpp---------------------
   #include "testthread.h"
   #include <iostream>
   //#include "moc_testthread.cpp"

   testThread::~testThread()
   {}

   testThread::testThread(const string& threadName, QThread* thread):QObject()
   {
      _threadName = threadName;
       moveToThread(thread);
       connect(thread, SIGNAL(started()),this,SLOT(start()));
   }

   void testThread::calculateSquare(int i)
   {
      cout<<_threadName<<" "<<i*i;
   }

   void testThread::start()
    {
       for(int i=0;i<10;++i)
       {
         emit requestCalculateSquare(i);
       }
         emit finished();
    }

     --------main.cpp--------------------------
    #include <iostream>
    #include <QtCore/QCoreApplication>
    #include <string> 
    #include "testthread.h"

    using namespace std;

    int main(int argc, char** argv)
    {
       QApplication app(argc,argv);
       string name1("Thread1");
       string name2("Thread2");
       QThread* thread1 = new QThread;
       QThread* thread2 = new QThread;
       testThread*  test1 = new testThread(name1, thread1);
       testThread* test2 = new testThread(name2, thread2);

         QObject::connect(test1,SIGNAL(requestCalculateSquare(int)),test2,SLOT(calculateSquare(int)));
QObject::connect(test2,SIGNAL(requestCalculateSquare(int)),test1,SLOT(calculateSquare(int)));
    QObject::connect(test1,SIGNAL(finished()),test2, SLOT(deleteLater()));
    QObject::connect(test1,SIGNAL(finished()),thread2, SLOT(quit()));
    QObject::connect(test2,SIGNAL(finished()),test1, SLOT(deleteLater()));
    QObject::connect(test2,SIGNAL(finished()),thread1, SLOT(quit()));

thread1->start();
thread2->start();

thread1->wait();
thread2->wait();

cout << "Hello World!" << endl;
return 0;
//return app.exec();
}

Ответы [ 2 ]

3 голосов
/ 04 марта 2012

Вы делаете несколько прикольных вещей.

1) Каждому QThread дважды вызывается start() - сначала в конструкторе testThread, затем снова в main().Второй вызов ничего не сделает, так как он уже запущен.

2) Когда вы запускаете QThread в конструкторе testThread, ваш цикл будет выполнять и испускать сигналы до того, как они будут подключены -это заставляет меня думать, что вы на самом деле не хотите запускать поток в конструкторе, и вместо этого оставляете его без запуска до тех пор, пока в main().

3) QThread::quit() не произойдет возврат цикла событий потока -это то, что вам не хватает.connect сигнал типа «выполнено» из testThread в слот quit, а затем QThread::wait() будет вести себя так, как вы ожидаете, с вызовами, возвращающимися после завершения циклов.

4) Iзнаю, что это всего лишь небольшая тестовая программа, но вы теряете память, поскольку вы не вызываете delete для ваших new объектов.Вам вообще не нужно здесь использовать new, все может быть размещено в стеке - как правило, лучшая идея.

0 голосов
/ 04 марта 2012

Не ждите, пока не выйдет основной поток.Ожидание STDIN или какого-либо другого ввода, возможно?

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

...