从QtConcurrent螺纹计算中获取项目序列号

时间:2014-01-19 15:47:28

标签: c++ multithreading qt qml qtconcurrent

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

总体目标:

我想从QML中查询,取消()或暂停()数字密集型计算。 到目前为止,这是按照我想要的方式工作,除了我无法访问计算中的序列号。这是a link that describes a similar QML setup

下面是我创建的小型测试应用的图片,用于封装我想要做的事情:

enter image description here

在上面的示例中,计算已接近完成,并且所有核心都已正常排队,从系统查询中可以看出:

enter image description here

但我真正想要做的是使用项目 IN THE 多线程计算本身的给定列表中的序列号。例如,一种方法可能是直接在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 

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

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

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

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

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

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

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

思考?建议?其他选择?感谢。


编辑:感谢用户2025983提供的帮助我解决此问题的见解。底线是我首先需要动态分配QList:

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

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

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

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

void mapFunction(int& n)

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

_futureWatcher.waitForFinished();

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

1 个答案:

答案 0 :(得分:1)

这里的问题是当mapTask()完成时你的QList超出了范围。 由于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