Qt: QtConcurrent - Почему указатель не меняется? - PullRequest
0 голосов
/ 13 февраля 2020

Я делаю свои первые шаги в QtConcurrent . Я пытаюсь реализовать итеративный расчет и, чтобы избежать копирования большого количества данных (в этом примере оно сокращено для демонстрационных целей), я реализую нечто подобное, например двойной буфер, в общем объекте данных (полученном из QSharedData) и доступ к которому осуществляется через QSharedDataPointer.

qtconcurrent_example.h

#ifndef QTCONCURRENT_EXAMPLE_H_INCLUDED
#define QTCONCURRENT_EXAMPLE_H_INCLUDED

#include <functional>
#include <QList>
#include <QDebug>
#include <QSharedData>

typedef QVector<double> StateType;

class StateData : public QSharedData
{
    StateType state_left;
    StateType state_right;
public:
    StateType* state_cur;
    StateType* state_new;

public:
    StateData(StateType initState){
        this->state_left = initState;
        this->state_right = StateType();
        this->state_right.resize(initState.length());
        this->state_cur = &(this->state_left);
        this->state_new = &(this->state_right);
    }
    void swap(){
        qInfo() << "## swap start ##"
                << " cur:" << QString::pointer(this->state_cur)
                << " new:" << QString::pointer(this->state_new);
        StateType* cur = this->state_cur;
        this->state_cur = this->state_new;
        this->state_new = cur;
        qInfo() << "## swap end   ##"
                << " cur:" << QString::pointer(this->state_cur)
                << " new:" << QString::pointer(this->state_new);
    }
};

typedef QSharedDataPointer<StateData> State;
typedef std::function<double(const StateType&)> Odefun;

class WorkItem
{
public:
    WorkItem(int index, State data, Odefun odefun){
        this->index = index;
        this->data = data;
        this->odefun = odefun;
    }
    int index;
    State data;
    Odefun odefun;
};


class QtConcurrent_example
{
    // shared data pointer to the state data
    State state;

public:
    QtConcurrent_example();
};

#endif // QTCONCURRENT_EXAMPLE_H_INCLUDED

qtconcurrent_example. cpp

#include "qtconcurrent_example.h"

#include <QtConcurrent>

QtConcurrent_example::QtConcurrent_example()
{
    // initialize state data and link the objet to the shared
    // data pointer
    StateType init = {1,2,3};
    state = new StateData(init);

    qInfo() << "\t" << QString::number(state.data()->state_cur->at(0))
            << "\t" << QString::number(state.data()->state_cur->at(1))
            << "\t" << QString::number(state.data()->state_cur->at(2))
            << "\tp:" << QString::pointer(state.data()->state_cur);

    QList<WorkItem> workSet;
    workSet.append( WorkItem( 0, state,
                          [](const StateType &s){
                              return s.at(0)*2;
                          } ));

    workSet.append( WorkItem( 1, state,
                          [](const StateType &s){
                              return s.at(1)*2;
                          } ));

    workSet.append( WorkItem( 2, state,
                          [](const StateType &s){
                              return s.at(2)*2;
                          } ));

    std::function<void(const WorkItem &)> step =
          [](const WorkItem &wi){
              qInfo() << "## step       ##"
                        << " cur:" << QString::pointer(wi.data.data()->state_cur)
                        << " new:" << QString::pointer(wi.data.data()->state_new);
                // apply ode at index
                auto r = wi.odefun(*wi.data.data()->state_cur);
                // apply integration
                r = wi.data.data()->state_cur->at(wi.index) + r*0.01;
                // store data
                wi.data.data()->state_new->replace(wi.index, r);
          };

    StateType* cur;
    for(int i=0; i<10; i++){

        cur = state.data()->state_cur;
        qInfo() << "apply blockingMap step"
                << "\tp:" << QString::pointer(cur);
        QtConcurrent::blockingMap(workSet, step);

        cur = state.data()->state_cur;
        qInfo() << "apply swap"
                << "\tp:" << QString::pointer(cur);
        state.data()->swap();

        cur = state.data()->state_cur;
        qInfo() << "  > i=" << QString::number(i)
                << "\t" << QString::number(cur->at(0))
                << "\t" << QString::number(cur->at(1))
                << "\t" << QString::number(cur->at(2))
                << "\tp:" << QString::pointer(cur);
    }


}

Соответствующий вывод:

     "1"     "2"     "3"    p: 0x55c3f5d06a08
## swap start ##  cur: 0x55c3f5d06a08  new: 0x55c3f5d06a10
## swap end   ##  cur: 0x55c3f5d06a10  new: 0x55c3f5d06a08
apply blockingMap step  p: 0x55c3f5d06a10
## step       ##  cur: 0x55c3f5d06a08  new: 0x55c3f5d06a10
## step       ##  cur: 0x55c3f5d06a10  new: 0x55c3f5d06a08
## step       ##  cur: 0x55c3f5d06a10  new: 0x55c3f5d06a08
apply swap  p: 0x55c3f5d06a10
## swap start ##  cur: 0x55c3f5d06a10  new: 0x55c3f5d06a08
## swap end   ##  cur: 0x55c3f5d06a08  new: 0x55c3f5d06a10
  > i= "0"   "1"     "0"     "0"    p: 0x55c3f5d06a08
apply blockingMap step  p: 0x55c3f5d06a08
## step       ##  cur: 0x55c3f5d06a08  new: 0x55c3f5d06a10
## step       ##  cur: 0x55c3f5d06a10  new: 0x55c3f5d06a08
## step       ##  cur: 0x55c3f5d06a10  new: 0x55c3f5d06a08
apply swap  p: 0x55c3f5d06a08
## swap start ##  cur: 0x55c3f5d06a08  new: 0x55c3f5d06a10
## swap end   ##  cur: 0x55c3f5d06a10  new: 0x55c3f5d06a08
  > i= "1"   "1.02"      "0"     "0"    p: 0x55c3f5d06a10
apply blockingMap step  p: 0x55c3f5d06a10
## step       ##  cur: 0x55c3f5d06a08  new: 0x55c3f5d06a10
## step       ##  cur: 0x55c3f5d06a10  new: 0x55c3f5d06a08
...

И я не понимаю, почему указатель state_cur всегда одинаков внутри QtConcurrent::blockingMap(workSet, step), даже если он изменяется снаружи (из-за swap).

Почему?


Мне кажется, что указатель будет исправлен, пока

    workSet.append( WorkItem( 0, state,
                          [](const StateType &s){
                              return s.at(0)*2;
                          } ));

Потому что: если я позвоню

state.data()->swap();

, между или за тремя workSet.append(...) вызывает, это влияет на указатель внутри соответствующего вызова, хотя указатель state_cur больше не меняется.


Удаление всех const не помогает - как и ожидалось.

...