Remy San
Remy San

Reputation: 525

Signal from Main Thread not reaching slot in Second Thread Qt 5

I am writing a program that captures an Image from the Camera every REFRESH_RATE milliseconds to send it to some calculation algorithm. I decided to time the launch of this algorithm using a QThread, but the algorithm is running on the main thread, because I need objects created before in this one. Anyway, this works well. The trouble begins when I try to shut the second thread down... Here's the code.

Camera:

class Camera : public QMainWindow
{
    Q_OBJECT

    public:
        Camera(QWidget *parent = 0){

             AlgoQThread = new QThread;
             myAlgoThreadWorker = new AlgoThreadWorker( (Camera *) this );
             myAlgoThreadWorker->moveToThread(AlgoQThread);

             //Launch The thread
             connect(AlgoQThread, SIGNAL(started()), myAlgoThreadWorker, SLOT(process())); 

             connect(myAlgoThreadWorker, SIGNAL(finished()), AlgoQThread, SLOT(quit())); 
             // The line meant to stop the thread at next loop
             connect(this, SIGNAL(stopAlgoThread()), myAlgoThreadWorker, SLOT(stopThread()));

             connect(myAlgoThreadWorker, SIGNAL(finished()), myAlgoThreadWorker, SLOT(deleteLater()));
             connect(AlgoQThread, SIGNAL(finished()), AlgoQThread, SLOT(deleteLater()));

             AlgoQThread->start();
         }

     private slots:
         void errorString(QString error);

         //This function is triggered by a signal sent by the method called in AlgoThreadWoker::process()
         void some_algorithm(){
             ...
             emit stopAlgoThread();
         }

     signals:
         void stopAlgoThread();

     private:
         QThread * AlgoQThread;
         AlgoThreadWorker * myAlgoThreadWorker;
};

algoThreadWorker:

class AlgoThreadWorker : public QObject
{
    Q_OBJECT

    public:
        AlgoThreadWorker(Camera * context){
            parentCamera = context;
        }
        Camera* parentCamera;

    public slots:
        void process(){
            while(1){

                QMutexLocker locker(&m_mutex);
                if (t_stop) break;

                parentCamera->isCapturingImage = true;

                //This triggers the some_algorithm() using a signal sent by imageCapture from main Thread
                parentCamera->imageCapture->capture();

                //Wait REFRESH_RATE millisecondes
                Sleep(REFRESH_RATE);

            }

            //Ends the thread
            emit finished();
        }

    private slots:
        void stopThread(){
            QMutexLocker locker(&m_mutex);
            t_stop = true;
        };

    signals:
        void finished();
        void error(QString);

    private:
        bool t_stop;
        QMutex m_mutex;
    };

And well, as you may have foresee, it doesn't work. I can launch some_algorithm() with no problems but I can't end the thread. The stopThread() slot isn't even launched, I've tested that already.

Upvotes: 1

Views: 1068

Answers (3)

Qt's event loop already provides for safe cross-thread slot call and event delivery. Your mistakes are mostly to do with incorrectly reimplementing what Qt already provides:

  1. Things are already thread-safe. Drop the mutex.

  2. thread->quit() works and will exit from the event loop running in the given thread. In a QThread, the thread will then finish,.

  3. Don't make your code non-portable for no reason (Sleep is Windows-specific). If you wish do things periodically, simply run a timer (QBasicTimer or QTimer).

This answer provides a complete example.

Upvotes: 0

Murat Şeker
Murat Şeker

Reputation: 1711

Since you are busy waiting in your while loop, the event loop never gets a chance to process the received signals.

qApp->processEvents() gives the control to your event loop in order to process the awaiting jobs.

Note that generally you do not have to call it yourself, Qt does it for you. In your case, it is neccessary because you have an endless loop which prevents Qt from doing its job.

Solution :

void process(){

    while(1){
        qApp->processEvents();
        ^^^^^^^^^^^^^^^^^^^^^^

        .....
    }

    //Ends the thread
    emit finished();
}

Upvotes: 3

Simon Warta
Simon Warta

Reputation: 11408

stopThread() is private and thus only accessible from AlgoThreadWorker.

Upvotes: 0

Related Questions