Я пытаюсь написать функцию, которая умножает массив в куче на константу, используя параллельный цикл for, но при попытке выполнить компиляцию в VisualStudio 2017 с / Qpar-report: 2 set, я получаю сообщение " Цикл не распараллелен по причине «1000». Я посмотрел его, и сообщение «Компилятор обнаружил зависимость данных в теле цикла.»:
https://docs.microsoft.com/en-us/cpp/error-messages/tool-errors/vectorizer-and-parallelizer-messages?view=vs-2017#BKMK_ReasonCode100x
В тексте описываются ситуации, когда (например) разные проходы зависят от результатов других проходов, но здесь это неприменимо. Единственная ситуация, о которой я могу подумать, это то, что оптимизатор может беспокоиться о том, что два массива перекрываются в памяти, но как вы убедите компилятор, что это не так?
Я попытался форсировать его с помощью оператора #pragma ivdep, и код компилируется, но функция зависает при вызове.
После долгих проблем я решил, что если я создам фиктивные массивы в стеке внутри функции и зациклю их, он будет успешно распараллеливаться. К сожалению, я не могу полагаться на массивы, которые я принимаю, чтобы они были достаточно маленькими, чтобы полностью копироваться в стек.
Я проверил SO и google на предмет других примеров параллельного выполнения простых операций над массивами, и все они используют выделенные в стеке массивы. Конечно, есть чистый способ распараллелить операцию на массиве кучи ??
#include "stdafx.h"
#include "CppUnitTest.h"
#include "../UnitsConversion/UnitsConversion.h"
using namespace Microsoft::VisualStudio::CppUnitTestFramework;
#define ARRAY_SIZE 10000000
double* testInD;
double* testOutD;
namespace UnitTest
{
TEST_CLASS(Parallel)
{
public:
TEST_CLASS_INITIALIZE(setup) {
testInD = new double[ARRAY_SIZE];
testOutD = new double[ARRAY_SIZE];
for (int i = 0; i < ARRAY_SIZE; i++) {
testInD[i] = (double)rand() / (double)RAND_MAX;
testOutD[i] = (double)rand() / (double)RAND_MAX;
}
}
TEST_CLASS_CLEANUP(cleanup) {
delete testInD;
delete testOutD;
}
TEST_METHOD(PressuresD)
{
Assert::AreEqual(
(int)1,
PressureD(
testInD,
testOutD,
ARRAY_SIZE
)
);
}
}
int __stdcall PressureD(
double* dblInValue,
double* dblOutValue,
int n) {
#pragma loop(hint_parallel(0))
for (int i = 0; i < n; ++i) {
dblOutValue[i] = dblInValue[i] * 5.0;
}
return 1;
}
По какой-то причине мне не повезло найти решение с Google или SO, хотя я думаю, что это будет распространенная проблема. Я что-то упустил?
EDIT:
Изменение цикла на следующее позволяет его распараллелить:
for (int i = 0; i < n; ++i) {
//dblOutValue[i] = dblInValue[i] * factor; (old version)
dblOutValue[i] *= factor;
}
Однако, когда я пытаюсь запустить модульное тестирование, код зависает и в конце концов (примерно через 15 секунд) прерывается. Код работает, когда я запускаю его в режиме отладки, но я на 95% уверен, что это потому, что он не паралеллизуется при запуске в отладке.