【问题标题】:Signal from Main Thread not reaching slot in Second Thread Qt 5来自主线程的信号未到达第二个线程 Qt 5 中的插槽
【发布时间】:2014-06-29 16:03:42
【问题描述】:

我正在编写一个程序,它每REFRESH_RATE 毫秒从相机捕获一张图像,以将其发送到某个计算算法。我决定使用QThread 来定时启动该算法,但该算法在主线程上运行,因为我需要在此之前创建的对象。 无论如何,这很好用。 当我尝试关闭第二个线程时,麻烦就开始了......这是代码。

相机:

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;
    };

好吧,正如您可能已经预见的那样,它不起作用。我可以毫无问题地启动some_algorithm(),但我无法结束线程。 stopThread() 插槽甚至还没有启动,我已经测试过了。

【问题讨论】:

  • 使用类名来命名对象是个坏主意。
  • 哦,搞错了;实际代码中不是这样的,抱歉。
  • 现在应该更好了。
  • 仅供参考,“睡眠”来自 windows.h,所以它的单位是毫秒。
  • 不错。 @Rems,我在寻找可能很快会在我自己的项目中实施的解决方案时,想出了一堆关于信号和槽的东西;)

标签: c++ multithreading qt


【解决方案1】:

由于您在 while 循环中忙于等待,因此事件循环永远没有机会处理接收到的信号。

qApp->processEvents() 将控制权交给您的事件循环,以处理等待中的作业。

请注意,通常您不必自己调用它,Qt 会为您完成。在你的情况下,这是必要的,因为你有一个无限循环,阻止 Qt 完成它的工作。

解决方案:

void process(){

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

        .....
    }

    //Ends the thread
    emit finished();
}

【讨论】:

    【解决方案2】:

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

    【讨论】:

    • stopThread() 可以通过信号槽机制访问,即使它是私有的。
    • 无论如何切换到公共槽并没有改变任何东西:stopThread() 仍然没有被触发。
    【解决方案3】:

    Qt 的事件循环已经提供了安全的跨线程槽调用和事件传递。您的错误主要与错误地重新实现 Qt 已经提供的功能有关:

    1. 事物已经是线程安全的。删除互斥锁。

    2. thread->quit() 工作并将退出在给定线程中运行的事件循环。在QThread 中,线程将结束。

    3. 不要无缘无故地使您的代码不可移植(Sleep 是特定于 Windows 的)。如果您希望定期执行操作,只需运行一个计时器(QBasicTimerQTimer)。

    This answer 提供了一个完整的例子。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-04-30
      • 1970-01-01
      • 2019-08-30
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多