qt - 打破在线程中的 QObject 的插槽内调用的循环
问题描述
AcquisitionManager 是一个生活在线程中的 QObject,我使用它从采集 PCI-Express 卡中获取样本:
m_acquisitionThread = new QThread(this);
m_acquisitionManager = new AcquisitionManager();
m_acquisitionManager->moveToThread(m_acquisitionThread);
m_acquisitionThread->start();
在我的应用程序代码(位于主线程中)中,我使用这个:
QMetaObject::invokeMethod(m_acquisitionManager, "executeDataAcquisition", Qt::QueuedConnection);
启动数据采集。
在“executeDataAcquisition”插槽内,我有一个循环:
for (size_t i = 0; i < numberOfLoops; ++i)
{
// blocking calls...
}
有时,我希望用户尽快中止采集,我考虑使用从主线程修改的布尔变量(+ volatile)。即使这不是非常线程安全的,布尔变量也只能由“从”线程读取,并且只能由主线程(主线程)写入:
for (size_t i = 0; i < numberOfLoops && m_bKeepAcquiring; ++i)
{
// blocking calls...
}
这样做是否正确?我在我工作的很多软件中都看到了这种技术,但我不知道这样做是否安全。还有其他技术吗?
解决方案
好吧,“即使这不是非常线程安全的”,这确实有点像代码风格问题。我的意思是,如果您不关心直接跨线程访问,那么我想这并不重要。
就我个人而言,我可能不会那样做。向工作线程添加一个方法来设置“停止”标志(甚至使用简单的互斥锁来保护标志,如QReadWriteLock
)非常简单。然后可以使用信号或排队的元方法调用“正确地”订购停止。如果除了主控制器线程之外不可能从任何地方设置标志,那么跳过互斥锁可能没问题,尽管它也是相当便宜的保险。
class AcquisitionManager ... {
public slots:
void requestStop() {
QWriteLocker lock(&m_flagMutex);
m_bStopRequested = true;
}
void executeDataAcquisition() {
for (size_t i = 0; i < numberOfLoops && !stopRequested(); ++i) {
// blocking calls...
QCoreApplication::processEvents(); // gives a chance for queued requestStop() call to be invoked
}
}
private:
inline bool stopRequested() {
QReadLocker lock(&m_flagMutex);
return m_bStopRequested;
}
bool m_bStopRequested = false;
QReadWriteLock m_flagMutex;
};
推荐阅读
- assembly - MOV 8 位到 16 位寄存器(al 到 bx)
- powerbi - 前几个月的 Power BI 累计和
- swift - 使用 Swift Package Manager 的 Swift IOS 库无法编译
- winforms - ContextMenuStrip 中的嵌套子菜单
- gitlab - GitlabCI:触发管道
- c# - 复杂的 linq 语句 - 嵌套组/where/sum/select
- snakemake - 如何从 config.yaml 分配多个路径?
- scala - 2个案例类的匹配值
- angular - 在 primeNg 下拉列表中使用 overlayVisible 属性
- groovy - 在groovy中以修剪格式获取数据库日期