从一个对象线程安全地使用const方法吗?

时间:2016-01-13 22:46:44

标签: c++ multithreading

我不确定这是不是重复,我查看了很多帖子,但它们似乎与我的问题不太接近。

我想从一个对象使用const方法同时更改其他对象。该程序基本上需要我在重力的影响下移动一个粒子,我想对所有粒子并行运行。我创建了一个物理类,在那个类中我有一个const方法来移动一个粒子对象。

以下是一些更好地了解我的示例课程。

/**
 * Particle.h
 */
#ifndef __Particle__sim__
#define __Particle__sim__

class Particle {
  private:
    double height;
    double velocity;
  public:
    const double getHeight() const;
    const double getVelocity() const;
    void setHeight(const double&);
    void setVelocity(const double&);
};

#endif
/**
 * Physics.h
 */
#ifndef __physics__sim__
#define __physics__sim__

#include <thread>
#include <vector>

#include "Particle.h"

class Physics {
  private:
    double gravity;
    double timeStep;
    void moveParticle(Particle&, const double) const;

  public:
    Physics(const double g, const double t);
    void moveParticles(std::vector<Particle>&, const double) const;
};

#endif
/**
 * Physics.cpp
 */
#include "Physics.h"

using namespace std;   

Physics::Physics(const double g, const double t) : gravity(g), timeStep(t) {}

void Physics::moveParticle(Particle& particle, const double time) const {
  // move particle under gravity
}

void Physics::moveParticles(vector<Particles>& particles, const double time) const {
  vector<thread> threads;
  threads.reserve(particles.size());

  for (auto& p : particles) {
    threads.push_back(thread(Physics::moveParticle&, this, std::ref(p), time));
  }
  for (auto& t : threads) {
    t.join();
  }
}

这基本上是我的主要

/**
 * main.cpp
 */

#include <vector>

#include "Physics.h"
#include "Particle.h"

using namespace std;

int main() {
  vector<Particle> particles;
  // insert 100,000 particles

  Physics physics = Physics(-9.81, 0.01);

  physics.moveParticles(particles, 5.0);    

  return 0;
}

physics.moveParticle(Particle&, const double)线程安全吗?

简短&amp;甜: 我想使用一个Physics对象的方法来使多个线程移动我的程序中的所有粒子,我不确定我写的const方法是否是线程安全的。我不明白为什么不能,但我无法证明这一点。

2 个答案:

答案 0 :(得分:2)

乍一看,这应该是线程安全的。

我们需要看到Particle :: setHeight的实现是绝对肯定的。如果它像写入全局数组那样做了什么?哪个会很傻,但我们无法确定。

然而,你的粒子看起来非常简单。什么是更安全的线程是不要改变它。使它们不可变,并在每次计算时创建一个新的。

您仍然可以通过将新粒子指定回旧粒子来更改它们。

然而,如果你真的想进入线程,那么这里的一个很棒的技术是拥有两个世界状态:上一个和下一个。这些与每个更新步骤交换。每个更新步骤都从先前读取并写入下一步。这使得其他线程(如图形显示)可以从之前读取,而不会经常锁定像粒子这样的小东西。

有了它,一个不可变的粒子根本不会减慢任何东西。实际上,编译器会将nextParticles[i] = updateParticle(prevParticles[i])的机器代码重写为直接赋值给它在内存中的最终位置。这是RVO或NRVO。

答案 1 :(得分:1)

对我来说看起来对线程安全。特别是,如果由每个产生的线程读取或写入的唯一(非不可变)数据是线程自己的对应粒子对象,则就线程而言,没有共享数据。 (当然,Physics对象本身是共享的,但是由于你没有在子线程的生命周期中修改Physics对象,所以Physics对象在操作期间实际上是不可变的/只读的,并且任何只读访问由生成的线程到物理对象将不会成为竞争条件的来源)