正确终止 QThread
Properly terminate a QThread
我有一个在后台进行图像采集的工人类。
void acq::run ()
{
while (m_started)
{
blocking_call();
}
emit workFinished();
}
void acq::start ()
{
m_started = true;
run();
}
void acq::stop ()
{
m_started = false;
}
start ()
;stop ()
是插槽,workFinished
是信号。
所以在我的 UI 类中,我启动了工作线程并将信号连接到插槽:
m_thread = new QThread;
m_worker = new acq();
m_worker->moveToThread(m_thread);
// When the thread starts, then start the acquisition.
connect(m_thread, SIGNAL (started ()), m_worker, SLOT (start ()));
// When the worker has finished, then close the thread
connect(m_worker, SIGNAL(workFinished()), m_thread, SLOT(quit()));
m_thread->start();
此时,我实现了插槽,closeEvent
void UIClass::closeEvent (QCloseEvent *event)
{
m_worker->stop(); // tell the worker to close
m_thread->wait(); // wait until the m_thread.quit() function is called
event->accept(); // quit the window
}
不幸的是,m_thread->wait()
正在阻塞。即使发出信号quit()
谢谢
编辑:
我添加了这两个连接:
connect(m_worker, SIGNAL(workFinished()), m_worker, SLOT(deleteLater()));
connect(m_thread, SIGNAL(finished()), m_thread, SLOT(deleteLater()));
和 Qdebug 进入acq::~acq()
打印的消息证明,调用停止,发出工作完成,发出删除后期()。
不同线程上的对象之间的正常信号/插槽连接要求接收对象的线程运行事件循环。
从理论上讲,您的接收方线程确实运行其事件循环,但事件循环正忙于执行start()
槽,因为run()
永远不会返回。
您要么需要取消阻塞接收器事件循环,要么使用Qt::DirectConnection
调用停止槽。
执行后者时,您需要注意该槽现在在发送方线程的上下文中调用,并且您需要保护m_started
免受并发访问。
除了使用自己的标志之外,您还可以使用QThread::requestInterruption()
和QThread::isInterruptionRequested()
添加
QCoreApplication::processEvents();
到你的循环,它会工作。
死锁的原因是对acq::run()
的调用会阻塞,并且没有时间在工作线程上执行acq::stop()
。
在Ralph Tandetzky和Kevin Krammer的帮助下,我终于找到了解决方案。
-
我没有用
m_worker->stop();
关闭线程,而是在worker事件循环中使用QMetaObject::invokeMethod(m_worker, "stop", Qt::ConnectionType::QueuedConnection);
和QCoreApplication::processEvents();
。行为不会改变,但我希望它能防止竞争条件或其他问题。 -
我使用自定义插槽,而不是使用:
connect(m_worker, SIGNAL(workFinished()), m_thread, SLOT(quit()));
:connect(m_worker, &Acq::workFinished, [=] { std::this_thread::sleep_for(std::chrono::milliseconds(100)); QMetaObject::invokeMethod(m_thread, "quit", Qt::ConnectionType::DirectConnection); });
我们使用 DirectConnection 是因为我们在无限循环之外,因此不会处理事件。
-
有了这个,我遇到了最后一个问题。
m_thread->wait
阻塞,我必须读取事件,否则,我的自定义插槽将永远不会被调用。所以在我的UI类QEventLoop m_loop
中添加了一个事件循环。
就在m_thread->wait()
之前,我写了m_loop.exec();
最后,在我的自定义插槽中,我放了m_loop.quit()
connect(m_worker, &Acq::workFinished, [=] { std::this_thread::sleep_for(std::chrono::milliseconds(100)); QMetaObject::invokeMethod(m_thread, "quit", Qt::ConnectionType::DirectConnection); m_loop.quit(); });
m_loop.exec()
进程事件,直到调用退出m_loop.quit()
。使用这种方法,我什至不需要m_thread->wait()
因为发出workFinished
时会调用m_loop.quit()
。我不再需要QMetaObject::invokeMethod(m_thread, "quit", Qt::ConnectionType::DirectConnection);
现在它像一个魅力
编辑:这个解决方案非常沉重和丑陋,Qt(https://www.qtdeveloperdays.com/sites/default/files/David%20Johnson%20qthreads.pdf)在我的情况下使用子类和请求中断是最糟糕的。
- OpenGL - 在抛出"__gnu_cxx::recursive_init_error"实例后终止调用?
- 多个文件的内存分配错误"在抛出 'std :: bad_alloc' what (): std :: bad_alloc 的实例后终止调用" [C++]
- 我收到以下错误:抛出'std::bad_alloc'实例后终止调用
- 为什么这个 c++ 代码打印出长度 5,当我打印出字符串时,程序会自动终止?
- 如何监控QThread
- 当我在其中一个线程执行中(在activemq-cpp中)捕获到特定值时,我如何终止/停止所有其他线程
- llvm构建器向基本块添加终止符
- 如何使用隔离>终止执行来停止所有线程
- 以线程安全的方式调用"QQuickPaintedItem::updateImage(const QImage&image)"(no QThread)
- 用于将C++代码转换为 Web 程序集的脚本未终止
- C++应用程序 MySQL odbc 数据库连接错误:在引发"otl_tmpl_exception<>"实例后终止调用
- 终止 QProcess 不会终止子进程
- 运行代码时,c++ 会终止进程
- 检测到堆栈粉碎:已终止 中止(核心已转储)
- 在输入句子时终止 std::out_of_range
- 二进制搜索的终止点
- MPI:检查是否有任何进程已终止
- 等待 qthread 终止的正确方法是什么?
- 正确终止 QThread
- 如何正确删除和终止QThread