2

QtConcurrent 命名空间非常适合简化多线程计算的管理。总的来说,这很好用,我已经能够按照 API 中描述的方式使用 QtConcurrent run()、map() 和其他变体。

总体的目标:

我想查询、取消()或暂停()来自 QML 的数字密集型计算。 到目前为止,这是我想要的方式,除了我无法访问计算中的序列号。 这是一个描述类似 QML 设置的链接

下面是我创建的用于封装我正在尝试做的事情的小型测试应用程序的图像:

在此处输入图像描述

在上面的示例中,计算几乎完成,所有核心都已正常工作,从系统查询中可以看出:

在此处输入图像描述

但我真正想做的是在多线程计算本身中使用给定项目列表中的序列。例如,一种方法可能是直接在 QList 或 QVector 中设置序列号(其他 C++ STL 容器也可以工作),如下所示:

void TaskDialog::mapTask()
{
    // Number of times the map function will be called:
    int N = 5;

    // Prepare the vector that we operate on with mapFunction:
    QList<int> vectorOfInts;
    for (int i = 0; i < N; i++) {
        vectorOfInts << i;
    }

    // Start the calc:
    QFuture<void> future = QtConcurrent::map(vectorOfInts, mapFunction);
    _futureWatcher.setFuture(future);
    //_futureWatcher.waitForFinished();
}

计算是非阻塞行:_futureWatcher.waitForFinished();注释掉,如上面的代码所示。请注意,当设置为非阻塞计算时,GUI 线程是响应式的,并且进度条会根据需要更新。

但是,当计算期间查询 QList 容器中的值时,似乎是未正确初始化数组时所期望的未初始化垃圾值。

下面是我正在调用的示例函数:

void mapFunction(int& n)
{
    // Check the n values:
    qDebug() << "n = " << n;
    /* Below is an arbitrary task but note that we left out n,
     * although normally we would want to use it): */
    const long work = 10000 * 10000 * 10;
    long s = 0;
    for (long j = 0; j < work; j++)
        s++;
}

的输出qDebug()是:

n =  30458288 
n =  204778 
n =  270195923 
n =  0 
n =  270385260 

s当以这种方式(非阻塞)映射计算时,n 值是无用的,但总和值是正确的(尽管未显示)。

现在,如果我取消注释该_futureWatcher.waitForFinished();行,那么我会得到预期值(顺序无关紧要):

n =  0 
n =  2 
n =  4 
n =  3 
n =  1

但在这种情况下,_futureWatcher.waitForFinished();启用后,我的 GUI 线程被阻止并且进度条不会更新。

如果目标是不阻塞主 GUI 线程,那么在启用阻塞的情况下使用 QtConcurrent::map() 会有什么好处?

其次,如何n在非阻塞情况下获得正确的值,让 GUI 保持响应并让进度条不断更新?

我唯一的选择可能是直接使用 QThread,但我想利用 QtConcurrent 中为我们设置的所有不错的工具。

想法?建议?其他选择?谢谢。


编辑:感谢 user2025983 的洞察力帮助我解决了这个问题。底线是我首先需要动态分配 QList:

QList<int>* vectorOfInts = new QList<int>;
for (int i = 0; i < N; i++)
    vectorOfInts->push_back(i);

接下来,vectorOfInts通过取消引用指针,通过引用传递给 map 函数,如下所示:

QFuture<void> future = QtConcurrent::map(*vectorOfInts, mapFunction);

另请注意,mapFunction 的原型保持不变:

void mapFunction(int& n)

然后一切正常:GUI 保持响应,进度条更新,值n全部正确等,无需通过函数添加阻塞:

_futureWatcher.waitForFinished();

希望这些额外的细节可以帮助别人。

4

1 回答 1

1

这里的问题是您的 QList 在完成时超出了范围mapTask()。由于mapFunction(int &n)通过引用获取参数,因此它获取对整数值的引用,这些值现在是超出范围的数组的一部分!因此,计算机可以随意使用该内存做任何事情,这就是您看到垃圾值的原因。如果您只是使用整数参数,我建议您按值传递参数,然后一切正常。

或者,如果您必须通过引用传递,您可以让 futureWatcher 在完成后删除数组。

    QList<int>* vectorOfInts = new QList<int>;
    // push back into structure
    connect(_futureWatcher, SIGNAL(finished()), vectorOfInts, SLOT(deleteLater()));
    // launch stuff
    QtConcurrent::map...
    // profit
于 2014-01-19T18:58:36.833 回答