Я делаю свои первые шаги в 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
не помогает - как и ожидалось.