Как сказать QThread дождаться завершения работы, а затем закончить?

У меня есть простое приложение, которое использует один рабочий поток. Этот рабочий поток запускается и инициализирует DownloadManager, который отвечает за загрузку файлов из сети. В моем основном классе приложения у меня есть СИГНАЛ finish() в потоке, который испускается до завершения DownloadManager.

Мой вопрос заключается в том, как заставить рабочий поток ждать, пока DownloadManager завершит свою работу.

Вот пример кода:

 class Main
 {
     m_DownloadWorker = new DownloadWorker(this);
     QObject::connect(pm_hotosDownloadWorker, SIGNAL(finished()), this, SLOT(DownloadWorkerFinished()));
     m_DownloadWorker->Execute();
     // do i need to do here something so the thread will wait ?

     .....


    void Main::DownloadWorkerFinished()
    {
        Log("DownloadWorkerFinished");
    }
 };


 class DownloadWorker : public QThread
 {
     void DownloadWorker::Execute()
     {

         // do i need to do here somthing so the thread will wait ? 
        start();
     }

     void DownloadWorker::run()
     {
         // do i need to do here somthing so the thread will wait ?
        DownloadManager* pDownloadManager = new DownloadManager(this);
        pDownloadManager->download();


     }
 };

 class DownloadManager: public QObject
 {
     // downloading stuff using Qt networkmanager 

     .....
     .....
 }

person user63898    schedule 10.04.2011    source источник
comment
это очень сбивает с толку. 1) что такое pm_hotosDownloadWorker? 2) Что делает QObject::connect(pm_hotosDownloadWorker, SIGNAL(finished()), this, SLOT(DownloadWorkerFinished())); иметь в виду? Что происходит внутри DownloadWorker::start()? 3) чтобы выяснить, нужно ли вам что-то делать, чтобы заставить поток ждать, проверьте, нужно ли вам что-то, сравнив ваши ожидания с тем, что происходит на самом деле / ​​в документе говорится, что должно произойти. 4) Почему есть 3 места, где вы хотите заблокировать выполнение?   -  person Ronny Brendel    schedule 10.04.2011
comment
1) я исправил это 2) он просто печатает сообщение о том, что поток завершен 3) ... 4) я знаю, что поток завершится только после завершения загрузки из DownloadManager   -  person user63898    schedule 10.04.2011


Ответы (2)


Вы можете использовать вызов QThread::exec() для запуска потока цикл событий. Поток будет выполнять его до тех пор, пока вы не скажете своему потоку выйти, вызвав QThread::exit( ). Таким образом, пример кода может выглядеть так:

void DownloadWorker::run()
 {
    DownloadManager* pDownloadManager = new DownloadManager(this);
    connect(pDownloadManager, SIGNAL(finished()), SLOT(exit()));
    connect(pDownloadManager, SIGNAL(error()), SLOT(exit()));
    pDownloadManager->download();
    exec();
 }

Это гарантировало бы вам, что ваш поток не завершится, пока не будет выдан сигнал "finished ()" вашего DownloadManager.

Примечание. Здесь я привел пример решения вашей проблемы, но я не знаю всего кода вашего приложения. Это означает, что нет гарантии, что этот код является потокобезопасным и непротиворечивым. Вам нужно позаботиться о мьютексах и всей правильной синхронизации самостоятельно. Будь очень осторожен ! Работа с таким «низкоуровневым» API потоков требует хорошего понимания многопоточного чтения.

надеюсь, это поможет

person Barbaris    schedule 10.04.2011

В тех случаях, когда у вас есть сигнал, который выдается при завершении асинхронной операции, вы всегда можете использовать QEventLoop, чтобы «превратить» асинхронную операцию в синхронную с текущим потоком. Он по-прежнему асинхронный, но поток будет "ждать" его завершения.

QNetworkAccessManager nam;
QEventLoop loop;
QNetworkReply *reply = nam.get(request); 
connect(reply, SIGNAL(finished()), &loop, SLOT(quit()));
loop.exec();

Итак, в основном вы помещаете это в свой класс DownloadManager, где вы хотите синхронно выполнять сетевой запрос. exec() вернется после вызова слота quit цикла.

person Tamás Szelei    schedule 10.04.2011
comment
у меня уже есть функция в моем финишном слоте, как я могу это сделать? - person user63898; 10.04.2011
comment
Ты имеешь в виду сигнал, да? Вы можете подключить несколько слотов к одному сигналу, без проблем. - person Tamás Szelei; 10.04.2011
comment
nam.get() вызывается перед сигналом, подключенным к слоту выхода из цикла. Не исключено, что готовый сигнал вызывается до вызова loop.exec() или состояния соединения. Q1: что произойдет, если сигнал будет отправлен до соединения? Q2: что происходит, когда сигнал передается до exec() и после connect()? @TamásSzelei - person Muhammet Ali Asan; 21.02.2017
comment
@MuhammetAliAsan Оба ваших вопроса сводятся к следующему: нет ли здесь условий гонки? Это зависит от того, где этот код выполняется. Если этот код выполняется в потоке отдельно от основного цикла событий приложения, может возникнуть состояние гонки. Если этот код выполняется в основном цикле событий (например, в слоте нажатия кнопки), тогда не может быть состояния гонки, потому что любые события ответа будут обрабатываться только после завершения текущего события (та самая функция, в которой мы находимся). - person Tamás Szelei; 21.02.2017