2012-08-24 23 views
5

Dużo przemyślałem i przeczytałem wiele artykułów zanim zadaję to pytanie tutaj. Żaden z artykułów nie dał mi właściwej odpowiedzi.QThread finished() connected to deletelater z QObject

http://mayaposch.wordpress.com/2011/11/01/how-to-really-truly-use-qthreads-the-full-explanation/

QThread* thread = new QThread; 
Worker* worker = new Worker(); 
worker->moveToThread(thread); 
connect(worker, SIGNAL(error(QString)), this, SLOT(errorString(QString))); 
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())); 
thread->start(); 

Pracownik obiekt ma powinowactwo nowej nici.

1> Pracownik zakończył sygnał wywołaj quit() na wątku. Spowoduje to zakończenie pętli zdarzeń wątku i zainicjowanie wątku zakończonego sygnałem.

2> Sygnał zakończony przez pracownika jest połączony z robotem deleteLater(). Zgodnie z instrukcją deleteLater()

** Planuje ten obiekt do usunięcia. Obiekt zostanie usunięty, gdy sterowanie powróci do pętli zdarzeń. Jeśli pętla Impreza> nie działa

kiedy ta funkcja jest wywoływana (np deleteLater() jest wywoływana na obiektu przed QCoreApplication :: exec()), obiekt zostanie usunięty po uruchomieniu pętli zdarzenia.

Należy zauważyć, że wprowadzenie i wyjście z nowej pętli zdarzeń (np. Poprzez otwarcie modalnego okna dialogowego) nie spowoduje odroczonego usunięcia; aby obiekt mógł zostać usunięty, kontrola musi wrócić do pętli zdarzeń, z której wywołano metodę deleteLater().

Uwaga: To można bezpiecznie wywołać tę funkcję więcej niż jeden raz; kiedy pierwszy odroczony wydarzenie delecja jest dostarczany wszelkie toczące się wydarzenia dla obiektu są usunięte z kolejki zdarzeń. **

Więc gdy nie ma eventloop, ponieważ wątek jest już wyjściu i to już podniesione gotowy sygnał i już nie będziemy zaczynać ponownie tego samego wątku. W takim przypadku funkcja deleteLater() nigdy nie będzie obsługiwana, ponieważ pętla zdarzeń nie istnieje, a obiekt roboczy nie zostanie w ogóle usunięty. Czy to nie powoduje wycieku pamięci.?

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

Jeśli uważamy, że zamiana dwóch wierszy będzie rozwiązać ten problem, to mam jeszcze jedno pytanie. QT wyraźnie stwierdza, że ​​kolejność wywoływania gniazd w momencie emisji sygnału jest nieokreślona.

Istnieje kilka komentarzy w powyższym łączu artykułu. Nawet autor nie był w stanie odpowiedzieć na pytanie, całkowicie

Odpowiedz

2
//! put the following code in constructor 
QThread *thread = new QThread; 
//! type of m_weakThread is QWeakPointer<QThread> 
m_weakThread = thread; 
Worker *worker = new Worker; 
//! type of m_weakWorker is QWeakPointer<Worker> 
m_weakWorker = worker; 
worker->moveToThread(thread); 
connect(worker, SIGNAL(error(QString)), this, SLOT(errorString(QString))); 
connect(thread, SIGNAL(started()), worker, SLOT(process())); 
connect(worker, SIGNAL(finished()), worker, SLOT(deleteLater())); 
//! instead of finished() signal, connect destroyed() signal to thread's quit() slot 
connect(worker, SIGNAL(destroyed()), thread, SLOT(quit())); 
connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater())); 
thread->start(); 

//! put the following code in destructor 
if (!m_weakThread.isNull()) { 
    QThread *thread = m_weakThread.data(); 
    if (thread->isRunning()) { 
     thread->quit(); 
     thread->wait(); 
    } 
} 
if (!m_weakWorker.isNull()) { 
    Worker *worker = m_weakWorker.data(); 
    m_weakWorker.clear(); //! optional, a little optimization 
    //! it's safe to release worker since the secondary thread exits 
    delete worker; 
} 
if (!m_weakThread.isNull()) { 
    QThread *thread = m_weakThread.data(); 
    m_weakThread.clear(); 
    //! it's safe to release thread since it exits and all objects in it has released 
    delete thread; 
} 
+0

nie możesz usuwać pracownika w stworzonym wątku obiektu. ponieważ został już przeniesiony do wątku za pomocą moveToThread. Czy możesz to wyjaśnić? – Srikan

+0

Polecam również przypisanie rodzica do 'QThread'.Ponieważ instancja 'QThread' jest częścią wątku, w którym została utworzona (w przeciwieństwie do wszelkich obiektów, które zostały przeniesione do niej lub jej metoda' run() '), jest całkowicie bezpieczne wykonywanie' thread = new QThread (this); 'jeśli' thread' ma być częścią innej klasy. Generalnie powinieneś unikać wywoływania 'delete', jeśli istnieje lepsze rozwiązanie nie-ręczne. Nawet w standardowym C++ masz inteligentne wskaźniki, a co nie, które ponoszą ciężar ręcznego oczyszczania ramion. – rbaleksandar