【问题标题】:C++ Parallel_For issuesC++ Parallel_For 问题
【发布时间】:2020-11-23 10:30:28
【问题描述】:

我目前正在为我的论文编写遗传算法,但在实现 parallel_for 循环时遇到了错误,这可能非常明显,但我不知道如何解决这个问题。

void evaluate_population_fitness(vector<Chromosome *> population) {
  std::for_each(std::execution::par_unseq, population.begin(), population.end(), [](Chromosome *item) {
    item->setLength(1 / calculate_Chromosome_length(item));
  });
}

这是实际的并行 for 循环,这里是它调用的函数:

double calculate_Chromosome_length(Chromosome *path) {
  double sum = 0;
  vector<City *> cities = path->getCities();
  for (int i = 0; i < cities.size()-1; i++) {
    sum += sqrt(pow(cities[i]->getPosX() - cities[i + 1]->getPosX(), 2)
                    + pow(cities[i]->getPosY() - cities[i + 1]->getPosY(), 2));
    cout << sum << std::endl;
  }
  cout << sum << std::endl;
  return sum;
}

不幸的是,这只是意味着它返回全零。而它实际上应该计算一些欧几里得距离。 作为参考,Chromosome 是一个对象,包含一个 double 类型的长度和一个对城市vector&lt;City *&gt; 的引用向量,一个城市被定义为一个 X、Y 整数和一个字符串 ID。 我真的很感谢这里的一些帮助。

以下是城市的生成方式:

std::vector<City *> generate_randomCity(int number_Of_Cities_to_generate) {
  vector<City *> vector = std::vector<City *>();
  if (number_Of_Cities_to_generate == 0) return vector;
  string city_name = "City";
  for (int i = 0; i < number_Of_Cities_to_generate; i++) {
    city_name += std::to_string(i);
    City city = City(city_name, randomNumber(0, 999), randomNumber(0, 999), i);
    vector.emplace_back(&city);
  }
  return vector;
}

【问题讨论】:

  • 我认为该错误与并行内的 sum 声明有关。
  • 我正在使用 Visual Studio 社区 2019 附带的最新 MSVC 编译器,我曾在某处看到它受支持并且我没有收到任何编译错误。
  • 我猜问题可能出在cities 的生成方式上。你确定指针是有效的并且指向不同的对象吗?
  • 我将编辑主帖以显示城市是如何生成的。

标签: c++ parallel-processing c++17


【解决方案1】:

如果您在调试器下运行代码,您可能会看到所有指针都指向同一个地址。而且那个地址是无效的(虽然调试器不能告诉你)。

您创建一个 local 对象City,当当前循环迭代完成时,该对象立即死亡。您存储在vector中的指针无效。

保持指针向量通常很少有意义,因此最好重新组织代码以返回 std::vector&lt;City&gt;

std::vector<City> generate_randomCity(int number_Of_Cities_to_generate) {
  vector<City> vector;
  //if (number_Of_Cities_to_generate == 0) return vector; //unnecessary, loop can run 0 times, no problem with that
  string city_name = "City";
  for (int i = 0; i < number_Of_Cities_to_generate; i++) {
    //city_name += std::to_string(i); //this will add the number forever, so 5th city gets name 'City01234'
    vector.emplace_back(city_name + std::to_string(i), randomNumber(0, 999), randomNumber(0, 999), i);
  }

  return vector;
}

如果您真的不想更改您的代码(您应该),您需要创建比其当前范围更有效的对象。这是通过new完成的

std::vector<City*> generate_randomCity(int number_Of_Cities_to_generate) {
  vector<City*> vector;
  //if (number_Of_Cities_to_generate == 0) return vector; //unnecessary, loop can run 0 times, no problem with that
  string city_name = "City";
  for (int i = 0; i < number_Of_Cities_to_generate; i++) {
    //city_name += std::to_string(i); //this will add the number forever, so 5th city gets name 'City01234'
    City* city = new City(city_name + std::to_string(i), randomNumber(0, 999), randomNumber(0, 999), i);
    vector.emplace_back(city);
  }
  return vector;
}

请注意,当您使用完这些指针时,您有责任使用 delete 释放它们。
确保您没有与vector&lt;Chromosome *&gt; population 相同的错误

【讨论】:

  • 很棒的答案,非常感谢您的帮助,我将通过并调整我的代码。
【解决方案2】:

您在 std::vector&lt;City*&gt; vector 中存储了一个指向局部变量的指针,这是未定义的行为。

std::vector<City *> generate_randomCity(int number_Of_Cities_to_generate) {
  vector<City *> vector = std::vector<City *>();
  if (number_Of_Cities_to_generate == 0) return vector;
  string city_name = "City";
  for (int i = 0; i < number_Of_Cities_to_generate; i++) {
    city_name += std::to_string(i);
    City city = City(city_name, randomNumber(0, 999), randomNumber(0, 999), i);
    // Storing a pointer to local variable
    vector.emplace_back(&city);
  }
  return vector;
}

简单地说,在堆上创建一个不限制对象生命周期的城市:

City* city = new City(city_name, randomNumber(0, 999), randomNumber(0, 999), i);
vector.push_back(city);

请注意,当您不再需要 City 对象时,您需要将其删除,因此,最好使用智能指针而不是 new

【讨论】:

  • 肯定会研究智能指针。我来自 Java 领域,所以肯定有点困惑,但这解决了我的错误。现在得到正确的返回值。谢谢!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-03-27
相关资源
最近更新 更多