2014-02-06 3 views
0

После долгих испытаний и изменений в моем приложении QT Visual Leak Detector определил источник досадной утечки (8 байтов). VLD сообщил, что приложение QT является чистым, за исключением указателя QThread*.QThread создает утечку памяти

Немного реализации фона: приложение моделируется как гибрид решения Джеффри Холмса, Bulk download of web pages using Qt. Благодаря Джеффри для более раннего решения!

Вопросы:

  • Почему QThread* не уничтожает себя, когда рабочий поток завершит свою работу?

  • Как я могу заставить QThread* удалить поток и рабочий объект, когда работа завершена?

  • Должно ли QThread быть реализовано по-разному?

Код:

void vqMDIChildDialog::processWorkQueue(bool bIsBC) 
{ 

if (m_listOfTables.isEmpty() && currentReplicationThreads == 0) 
{ 
} 
else if (!m_listOfTables.isEmpty()) 
{ 
    for (int i = 0; i < maxReplicationThreads && !m_listOfTables.isEmpty();i++) 
    { 
     QThread *thread = new QThread; 
     QPointer<vcSharedDataQt> worker = new vcSharedDataQt(); 
     worker->moveToThread(thread); 
     QString tmpTableName (m_listOfTables.dequeue()); 
     worker->setParentObject(this); 
     // 
     // set properties on the worker object. 
     // 
     connect(thread, SIGNAL(started()), worker, SLOT(process())); 
     connect(worker, SIGNAL(finished()), thread, SLOT(quit())); 
     connect(worker, SIGNAL(finished()), worker, SLOT(deleteLater())); 
     connect(thread, SIGNAL(finished()), thread,SLOT(deleteLater())); 

     connect(worker, 
      SIGNAL(updateMessageFromThread( const QString&, 
          const QString&, 
          const QString&, 
          const QString&, 
          const QString&, 
          const QString&, 
          const QString&)), 

      this, 
      SLOT(UpdateStatusBarFromThread(const QString&, 
          const QString&, 
          const QString&, 
          const QString&, 
          const QString&, 
          const QString&, 
          const QString&))); 

     thread->setObjectName(worker->getUniqueKey()); 

     thread->start(); 
     currentReplicationThreads ++; 
    } 
} 

} 

Стек не позволил бы мне ответить на этот вопрос так:

Функция была прикрытый QMutex:

mutex.lock(); 
processWorkQueue(); 
mutex.unlock(); 

Это вызвало память протечь. QThread, по-видимому, не может быть уничтожен при завершении рабочего потока. Я удалил мьютекс, и VLD сообщает об утечке памяти с QThread.

+0

Ваше использование 'QPointer' бессмысленно :) –

+0

Какая версия Qt вы используете? (Поведение QThread deleteLater() изменилось вокруг 4.8.) –

+0

Спасибо за обновление и комментарии: Open - QT 5.2.0 –

ответ

2
  1. A QThread не знает, когда его работа будет выполнена. Вы можете ответить на свой вопрос, подумав о том, как вы это реализуете.

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

    Возможно, вы захотите прекратить поток, если их больше нет QObject s, у которых есть нить как нить. Это, безусловно, может быть реализовано как необязательное поведение в QThread, но будет ли это изменение принятым, я не знаю. Это не должно быть поведение по умолчанию, поскольку во многих ситуациях постоянное разрушение и повторное создание потоков просто бесполезно - можно было бы сохранить поток, на котором нет объектов.

    В конечном счете только вы знаете, когда работа потока выполнена. Ваш рабочий объект может вызывать thead()->quit() или он может излучать сигнал, когда это будет сделано - как и вы.

  2. A QThread не может уничтожить себя, когда работа выполнена, поскольку потоки перезапускаемы. У вас есть полный контроль над временем жизни нитки, поэтому вы, безусловно, можете уничтожить его, когда его работа будет завершена, и вы уже делаете, только вы делаете это неправильно.

  3. Ваша проблема действительно в том порядке, в котором вы хотите, чтобы что-то произошло. Операция deleteLater выполняется контуром события. Если цикл событий потока не запущен, deleteLater является NO-OP.

    Итак, прежде всего, ваши соединения должны быть сделано таким образом, что они образуют каскад, который может выполняться только в хорошо определенный порядок:

    connect(thread, SIGNAL(started()), worker, SLOT(process())); 
    connect(worker, SIGNAL(finished()), worker, SLOT(deleteLater())); 
    connect(worker, SIGNAL(destroyed()), thread, SLOT(quit())); 
    connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater())); 
    

    Затем, вы должны убедиться, что нить, где ваш processWorkQueue метод работает не заблокирован и имеет шанс для его цикл событий для продолжения. Именно этот цикл события будет обрабатывать удаление потока.

    Как отметил AlexP, это не работает в Qt 4.7 или более ранней версии, так как все эти версии имели ошибку в реализации QThread. «Поведение QThread изменилось» - это эвфемизм для «была уродливая ошибка, которая окончательно была исправлена».

  4. Ваше соединение является чрезмерно подробным. Вы можете отбрасывать пробелы и ссылку/const-ссылку из подписи. Третий аргумент также является необязательным, если он равен this. Он должен выглядеть следующим образом:

    connect(worker,          
         SIGNAL(updateMessageFromThread(QString,QString,QString,QString, 
                 QString,QString,QString)), 
         SLOT(updateStatusBarFromThread(QString,QString,QString,QString, 
                 QString,QString,QString))); 
    
0

Ответы:

  • Почему QThread* не уничтожает себя, когда рабочий поток завершит свою работу?

Поскольку существуют различные способы использования QThread, в которых по крайней мере один должен иметь возможность запрашивать состояния нитей или членов класса после завершения работника. Также поток можно перезапустить.

  • Как я могу заставить QThread* удалить поток и рабочий объект, когда работа завершена?

Сигнал finished должен быть достаточным для того, чтобы вы могли вызвать слот, удаляющий оба.

  • Должно ли QThread быть реализовано по-разному?

Существуют различные варианты реализации для разных ситуаций. http://qt-project.org/doc/qt-5.0/qtcore/thread-basics.html

 Смежные вопросы

  • Нет связанных вопросов^_^