Пространство имен QtConcurrent действительно отлично подходит для упрощения управления многопоточными вычислениями. В целом, это прекрасно работает, и я смог использовать QtConcurrent run (), map () и другие варианты так, как они описаны в API.
Я хотел бы запросить, отменить () или pause () численное вычисление из 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();
закомментировано, как показано в коде выше. Обратите внимание, что при настройке в качестве неблокирующего вычисления поток графического интерфейса реагирует, и индикатор выполнения обновляется по желанию.
Но когда во время вычисления запрашиваются значения в контейнере 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 заблокирован, и индикатор выполнения не обновляется.
В чем тогда будет преимущество использования QtConcurrent :: map () с включенной блокировкой, если цель не блокировать основной поток GUI?
Во-вторых, как можно получить правильные значения 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)
И тогда все работает правильно: графический интерфейс остался отзывчивым, индикатор выполнения обновлен, значения n
все правильно и т.д., БЕЗ необходимости добавлять блокировку через функцию:
_futureWatcher.waitForFinished();
Надеюсь, что эти дополнительные детали могут помочь кому-то еще.
Проблема в том, что ваш 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
Других решений пока нет …