我有一个线程,生产者和类消费者。消费者在QML注册,生产者与消费者联系。生产者将数据发送给消费者,因此消费者可以更新模型和GUI。
代码看起来像这样:
主要功能:
int main(int argc, char ** argv)
{
QGuiApplication app(argc, argv);
Producer producer;
Consumer consumer;
/* Connect signals between producer and consumer */
...
...
QQuickView view;
/* Set root context */
QQmlContext *ctxt = view.rootContext();
producer.start();
ctxt->setContextProperty("consumer", &consumer);
/*Connect signals between consumer and QML*/
...
view.show();
return app.exec();
}
制片人:
class Producer : public QThread
{
Q_OBJECT
protected:
void run()
{
while(true) {
if (someFlag == true)
{
// do some work
// emit signal with data to consumer
}
}
}
signals:
// Signals for sending data
};
问题是如何在按下应用程序退出时正确停止线程生产者?
答案 0 :(得分:2)
而不是while(true)
检查"应该结束"条件,例如isInterruptionRequested()
。
然后,在main()
中,在返回之前,告诉线程停止,例如在帖子上使用QThread::requestInterruption
然后wait
view.show();
const int ret = app.exec();
producer.requestInterruption();
producer.wait();
return ret;
答案 1 :(得分:0)
我有一个建议:
我的做法是,注册Windows关闭事件并在其中进行任何类型的清洁活动。
下面的伪代码。尽量使其适合您的应用程序。
class CloseEventFilter : public QObject
{
Q_OBJECT
public:
CloseEventFilter(QObject *parent) : QObject(parent) {}
protected:
bool eventFilter(QObject *obj, QEvent *event)
{
if (event->type() == QEvent::Close)
{
// Destroy your thread here.
producer->exit();//Make your thread available
//... may be global....producer is derived from QThread.
}
return QObject::eventFilter(obj, event)
}
}
};
//Registering window
QGuiApplication *app = new QGuiApplication(argc,argv);
QWindow* qtwindow = new QWindow();
CloseEventFilter *closeFilter = new CloseEventFilter(window);
qtwindow >installEventFilter(closeFilter);
为什么线程退出功能(来自文档)
void QThread :: exit(int returnCode = 0)
告诉线程的事件循环以退回代码退出。
调用此函数后,线程离开事件循环并从调用返回到QEventLoop :: exec()。 QEventLoop :: exec()函数返回returnCode。
按照惯例,returnCode为0表示成功,任何非零值表示错误。
请注意,与同名的C库函数不同,此函数会返回调用者 - 事件处理会停止。
在此线程中不再启动QEventLoops,直到再次调用QThread :: exec()。如果QThread :: exec()中的eventloop没有运行,那么下一次调用QThread :: exec()也会立即返回。
另见quit()和QEventLoop。
答案 2 :(得分:0)
当没有工作要做时,while (true) if (someFlag)
循环会将CPU固定在100%。你不想要那个!
唉,没有必要让Producer
成为QThread
。它可以是一个普通的QObject
。有不同的方法。
您可以使用零持续时间计时器使事件循环在线程中保持活动状态:
class Producer : public QObject
{
Q_OBJECT
QBasicTimer m_timer;
void timerEvent(QTimerEvent * ev) override {
if (ev->timerId() == m_timer.timerId())
doWorkChunk();
}
void doWorkChunk() {
...
emit hasData(...);
}
public:
Producer(QObject * parent = nullptr) : QObject{parent} {
connect(this, &Producer::start, this, [this]{ m_timer.start(this, 0); });
connect(this, &Producer::stop, this, [this]{ m_timer.stop(); });
}
Q_SIGNAL void start();
Q_SIGNAL void stop();
Q_SIGNAL void hasData(const DataType &);
};
不是设置/清除标记,而是调用start()
和stop()
。然后你可以将生产者移动到任何线程并且它可以正常工作,在退出时做正确的事情(将事情包装起来干净地):
class Thread : public QThread {
using QThread::run;
public:
~Thread() { quit(); wait(); }
};
int main(int argc, char ** argv) {
QCoreApplication app{argc, argv};
Producer producer;
Thread thread; // must come after producer above, the order has meaning!
producer.moveToThread(&thread);
thread.start();
return app.exec();
}
您也可以使用Qt Concurrent框架:
class Producer : public QObject {
{
Q_OBJECT
volatile bool m_active = false;
void doWorkChunk() {
...
emit hasData();
}
void doWork() {
while (m_active) doWorkChunk();
}
public:
using QObject::QObject;
~Producer() { stop(); }
void start() {
m_active = true;
QtConcurrent::run(this, &Producer::doWork);
}
void stop() {
m_active = false;
}
Q_SIGNAL void hasData(const DataType &);
};