【发布时间】:2021-02-18 01:42:29
【问题描述】:
我正在研究一种绘图算法。为此,我从主 GUI 线程中的 DAQ 板获取数据,然后将数据发送到工作线程进行处理,工作线程发出带有新 QImage 的信号,我将其显示为我的图形用户界面。问题在于函数,我们称之为generateImage(),计算和生成QImage 需要很长时间(约50-70 毫秒,取决于数据长度),并且在这段时间之间可能会有另一组数据到达要求工作线程从头开始重新计算绘图。我希望generateImage() 放弃计算并在新数据到达时从头开始重新开始计算。我的方法是设置一个成员布尔变量,我们称之为b_abort_,并检查它是否在generateImage() 和return 内设置为true,如果它是真的,在generateImage() 之外它始终保持为真,我只设置它在调用 generateImage() 之前为 false。
所有这些都发生在工作线程中,我将QObject 子类化并使用moveToThread() 将其移至工作线程。
开始计算的函数:
void WorkerThread::startCalc()
{
b_abort_ = false;
generateImage();
// if b_abort_ is set to true, generateImage() will return prematurely
if(b_abort_)
emit calcFinished();
else
b_abort_ = true;
}
进行所有计算并生成图像的功能:
void WorkerThread::generateImage()
{
/* Calculation of some parts */
for(int ii = 0; ii < Rawdata.length(); ++ii) // Starting main time consuming loop
{
if(b_abort_)
return;
/* Perform calculation for one data point from Rawdata */
}
// data calculation complete, now it's time to generate QImage
// before that I check if b_abort_ is set to true
if(b_abort_)
return;
for(int ii = 0; ii < CalculatedData.length(); ++ii) // plotting calculated data on QImage
{
if(b_abort_)
return;
/* plot one data point from CalculatedData vector */
}
// generation of QImage finished, time to send the signal
emit renderedPlot(image); // image is a QImage object
}
在我的工作线程中,我有一个从主 GUI 线程接收数据的插槽,它被配置为 Qt::QueuedConnection(默认)作为连接类型:
void WorkerThread::receiveData(QVector<double> data)
{
if(!b_abort_) // check if calculation is still running
{
QEventLoop loop;
connect(this, &WorkerThread::calcFinished, &loop, &QEventLoop::quit);
b_abort_ = true; // set it to true and wait for calculation to stop
loop.exec();
// start new calculation
RawData = data;
startClac();
}
else
{
RawData = data;
startClac();
}
}
当我在我的主 GUI 线程中使用这种方法时,generateImage() 函数会阻塞所有事件循环,并且我的 GUI 冻结,这让我认为在单个线程(主 GUI 线程或工作线程)中只有一个函数可以一次运行,因此在线程的事件循环返回以处理其他函数之前,不会应用 b_abort_ 中的任何更改。使用WorkerThread 时,很难验证这是否有效,有时它可以正常工作,而其他时候它会产生 bad allocation 错误,看起来好像它不起作用(尽管可能是因为完全不同的原因,我不确定)。我想问问您的意见,这是过早停止长时间运行的计算的正确方法吗?有没有其他比我目前的方法更强大的方法可以使用?
【问题讨论】:
-
这能回答你的问题吗? C++0x thread interruption
-
@UlrichEckhardt 不,我正在寻找的是从调用它的同一个线程内部停止一个长时间运行的函数,而不是从另一个线程停止/终止。
-
“在单个线程内 [...] 一次只能运行一个函数”——就是这种情况。我宁愿换一种说法:一个线程从一个地方执行代码。当然,那个地方可以在不同的功能之间移动,但不能同时在两个地方。
-
那个线程已经在做某事,所以不是真的。您可以使用 POSIX 信号/处理程序,但它的可移植性较差(并且标准 C++ 接口还不够,因为您需要
pthread_kill和/或pthread_sigmask才能完成这项工作)。这些都不会自动与 Qt 信号一起工作,因此您仍然需要在主线程中执行一些代码来发送该信号。 -
重要的部分不是哪个线程设置它(但请再次阅读下面有关“以某种方式同步”的答案),而是执行某些操作的线程无法设置它,反之亦然。一个线程可以在不同的事情之间交替,但它不能同时做两件事。顺便说一句:我不确定这是不是误解,但是如果您在某处有 C++
QThread或std::thread对象,那不是线程!这更像是std::fstream是一个文件,它是一个 C++ 对象,可用于与线程交互,以防万一你的误解。
标签: c++ multithreading qt c++17