我正在编写一个程序,每隔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()
插槽甚至没有启动,我已经测试过了。
答案 0 :(得分:2)
由于您在while循环中忙着等待,事件循环永远不会有机会处理接收到的信号。
qApp->processEvents()
为您的事件循环提供控制权,以便处理等待的作业。
请注意,通常您不必自己调用,Qt会为您完成。在你的情况下,它是必要的,因为你有一个无限循环阻止Qt完成它的工作。
解决方案:
void process(){
while(1){
qApp->processEvents();
^^^^^^^^^^^^^^^^^^^^^^
.....
}
//Ends the thread
emit finished();
}
答案 1 :(得分:0)
stopThread()
是私有的,因此只能从AlgoThreadWorker
访问。
答案 2 :(得分:0)
Qt的事件循环已经提供了安全的跨线程插槽调用和事件传递。你的错误主要与错误地重新实现Qt已经提供的内容有关:
事情已经是线程安全的。放下互斥锁。
thread->quit()
有效并将退出给定线程中运行的事件循环。在QThread
中,线程将完成,。
不要让您的代码无法移植(Sleep
是特定于Windows的)。如果您希望定期执行操作,只需运行计时器(QBasicTimer
或QTimer
)。
This answer提供了一个完整的示例。