据推测,停止相机线程会很快,你不应该忽略该事件。只需等到相机线程完成,然后从closeEvent
. closeEvent
甚至不需要参与。您并不真正关心窗口是否关闭,您关心的是应用程序事件循环是否已退出。
无需与图像采集卡类交互即可轻松确定相机线程何时结束。QtConcurrent::run
在取自全局线程池的线程上执行仿函数,也就是QThreadPool::globalInstance()
. 该activeThreadCount
方法返回忙于提交给它们的工作的线程数。
您可以按如下方式实现它:
class CameraStopper() {
Q_DISABLE_COPY(CameraStopper)
AbstractGrabber m_camera;
public:
explicit CameraStopper(AbstractGrabber * cam) : m_camera(cam) {}
~CameraStopper() {
m_camera->stop();
while (QThreadPool::globalInstance()->activeThreadCount())
QThread::yieldCurrentThread();
}
}
AbstractGrabber * MainWindow::camera() const { return camera1; }
int main(int argc, char ** argv) {
QApplication app(argc, argv);
MainWindow w;
CameraStopper stopper(w.camera());
w.show();
return app.exec();
}
这当然假设全局池中没有其他线程被卡在没有发出停止信号的事情上。CameraStopper
需要向所有此类异步任务发出停止信号。还要确保如果您通过 保留了任何线程reserveThread
,它们会在您等待相机停止之前正确释放。
您可以做的另一件事是使用一些每线程标志来停止线程。在 Qt 5.2 之前,这样的标志只有在线程中运行时才可用QEventLoop
- 调用QThread::quit()
该线程的实例将结束事件循环。从 Qt 5.2 开始,还有另一个独立于事件循环的标志。该标志是通过设置的QThread::requestInterruption
,并通过检查QThread::isInterruptionRequested
。
您需要保留一个全局线程列表,以便您可以轻松地将它们全部退出,因为QThreadPool
不会暴露其线程。可以这样做:
class ThreadRegistry {
Q_DISABLE_COPY(ThreadRegistry)
friend class ThreadRegistration;
QMutex m_mutex;
QList<QThread*> m_threads;
static QScopedPointer<ThreadRegistry> m_instance;
static ThreadRegistry * instance() {
if (!m_instance) m_instance.reset(new ThreadRegistry);
return m_instance;
}
public:
ThreadRegistry() {}
~ThreadRegistry() { quitThreads(); waitThreads(); }
void quitThreads() {
QMutexLocker lock(&m_mutex);
QList<QThread*> & threads(m_threads);
for (auto thread : threads) {
thread->quit(); // Quit the thread's event loop, if any
#if QT_VERSION>=QT_VERSION_CHECK(5,2,0)
thread->requestCancellation();
#endif
}
}
void waitThreads() {
forever {
QMutexLocker lock(&m_mutex);
int threadCount = m_threads.count();
lock.unlock();
if (!threadCount) break;
QThread::yieldCurrentThread();
}
}
};
class ThreadRegistration {
Q_DISABLE_COPY(ThreadRegistration)
public:
ThreadRegistration() {
QMutexLocker lock(&ThreadRegistry::instance()->m_mutex);
ThreadRegistry::instance()->m_threads << QThread::currentThread();
}
~ThreadRegistration() {
QMutexLocker lock(&ThreadRegistry::instance()->m_mutex);
ThreadRegistry::instance()->m_threads.removeAll(QThread::currentThread());
}
};
最后,对于 Qt 5.2 及更高版本,runnable 如下所示:
QtConcurrent::run([this]{
ThreadRegistration reg;
while (!QThread::currentThread()->isInterruptionRequested()) {
frame = captureFrame();
//Do stuff
}
}
对于 Qt 5.0 和 5.1,只要事件循环没有退出,您就可以利用零超时计时器连续运行一些代码:
QtConcurrent::run([this]{
ThreadRegistration reg;
QTimer timer;
timer.setInterval(0);
timer.setSingleShot(false);
timer.start();
QObject::connect(&timer, &QTimer::timeout, [this]{
frame = captureFrame();
//Do stuff
}
QEventLoop loop;
loop.run();
}
main
看起来如下:
int main(int argc, char ** argv) {
QApplication app(argc, argv);
ThreadRegistry registry;
MainWindow w;
w.show();
return app.exec();
// ThreadRegistry's destructor will stop the threads
// and wait for them to finish
}