简体   繁体   English

来自主线程的信号未到达第二线程Qt 5中的插槽

[英]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. 我正在编写一个程序,每REFRESH_RATE毫秒捕获一次来自相机的图像,然后将其发送到某种计算算法。 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. 我决定使用QThread来确定该算法的启动时间,但是该算法正在主线程上运行,因为我需要在此之前创建对象。 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: 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. 我可以some_algorithm()启动some_algorithm() ,但无法结束线程。 The stopThread() slot isn't even launched, I've tested that already. stopThread()插槽甚至没有启动,我已经测试过了。

Since you are busy waiting in your while loop, the event loop never gets a chance to process the received signals. 由于您在while循环中忙于等待,因此事件循环永远不会有机会处理接收到的信号。

qApp->processEvents() gives the control to your event loop in order to process the awaiting jobs. qApp->processEvents()将控制权交给事件循环,以便处理等待的作业。

Note that generally you do not have to call it yourself, Qt does it for you. 请注意,通常您不必自己调用它,Qt会为您调用它。 In your case, it is neccessary because you have an endless loop which prevents Qt from doing its job. 在您的情况下,这是必要的,因为您有一个无限循环,这会阻止Qt执行其工作。

Solution : 解决方案:

void process(){

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

        .....
    }

    //Ends the thread
    emit finished();
}

stopThread()是私有的,因此只能从AlgoThreadWorker访问。

Qt's event loop already provides for safe cross-thread slot call and event delivery. Qt的事件循环已经提供了安全的跨线程插槽调用和事件传递。 Your mistakes are mostly to do with incorrectly reimplementing what Qt already provides: 您的错误主要与错误地重新实现Qt已经提供的功能有关:

  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. thread->quit()有效,并且将从给定线程中运行的事件循环退出。 In a QThread , the thread will then finish,. QThread ,线程将完成。

  3. Don't make your code non-portable for no reason ( Sleep is Windows-specific). 不要无缘无故地使代码不可移植( Sleep是特定于Windows的)。 If you wish do things periodically, simply run a timer ( QBasicTimer or QTimer ). 如果您希望定期执行操作,只需运行一个计时器( QBasicTimerQTimer )。

This answer provides a complete example. 此答案提供了完整的示例。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM