C++ 多线程和动态数组/矩阵运算';s

C++ 多线程和动态数组/矩阵运算';s,c++,multithreading,linear-algebra,dynamic-arrays,C++,Multithreading,Linear Algebra,Dynamic Arrays,我目前正在写一个物理模拟(t.b.m.p.解一个随机微分方程),我需要将其并行化。 现在,这可以通过MPI实现,我想我在将来的某个时候必须这样做,但目前我想利用我本地机器的所有8个内核。一个参数设置的正常运行需要2-17小时。因此,我认为应该利用多线程,特别是以下函数应该并行执行。此函数基本上为Nstepstimesteps求解相同的SDENrep时间。将每个线程的结果取平均值并存储到Nthreads x Nsteps数组JpmArr的单独一行中 double **JpmArr; void wo

我目前正在写一个物理模拟(t.b.m.p.解一个随机微分方程),我需要将其并行化。
现在,这可以通过MPI实现,我想我在将来的某个时候必须这样做,但目前我想利用我本地机器的所有8个内核。一个参数设置的正常运行需要2-17小时。因此,我认为应该利用多线程,特别是以下函数应该并行执行。此函数基本上为
Nsteps
timesteps求解相同的SDE
Nrep
时间。将每个线程的结果取平均值并存储到
Nthreads x Nsteps
数组
JpmArr
的单独一行中

double **JpmArr;
void worker(const dtype gamma, const dtype dt, const uint seed, const uint Nsteps, const uint Nrep,\
            const ESpMatD& Jplus, const ESpMatD& Jminus, const ESpMatD& Jz, const uint tId ){


dtype dW(0), stdDev( sqrt(dt) );

std::normal_distribution<> WienerDistr(0, stdDev);

//create the arrays for the values of <t|J+J-|t>
 dtype* JpmExpect = JpmArr[tId];

//execute Nrep repetitions of the experiment
for (uint r(0); r < Nrep; ++r) {
    //reinitialize the wave function
    psiVecArr[tId] = globalIstate;
    //<t|J+J-|t>
    tmpVecArr[tId] = Jminus* psiVecArr[tId];
    JpmExpect[0] += tmpVecArr[tId].squaredNorm();
    //iterate over the timesteps
    for (uint s(1); s < Nsteps; ++s) {

        //get a random number
        dW = WienerDistr(RNGarr[tId]);

        //execute one step of the RK-s.o. 1 scheme
        tmpPsiVecArr[tId] = F2(gamma, std::ref(Jminus), std::ref(psiVecArr[tId]) );
        tmpVecArr[tId] = psiVecArr[tId] + tmpPsiVecArr[tId] * sqrt(dt);
        psiVecArr[tId] = psiVecArr[tId] + F1(gamma, std::ref(Jminus), std::ref(Jplus),   std::ref(psiVecArr[tId])) * dt + tmpPsiVecArr[tId] * dW \
 + 0.5 * (F2(gamma, std::ref(Jminus), std::ref(tmpVecArr[tId]) ) - F2(gamma, std::ref(Jminus), std::ref(psiVecArr[tId]))) *(dW * dW - dt) / sqrt(dt);

        //normalise
        psiVecArr[tId].normalize();
        //compute <t|J+J-|t>
        tmpVecArr[tId] = Jminus* psiVecArr[tId];
        JpmExpect[s] += tmpVecArr[tId].squaredNorm();
    }
}


//average over the repetitions
for (uint j(0); j < Nsteps; ++j) {
    JpmExpect[j] /= Nrep;
}
}
double**JpmArr;
无效工作程序(常数数据类型gamma、常数数据类型dt、常数种子、常数Nsteps、常数Nrep、\
const Espmatt&Jplus、const Espmatt&Jminus、const Espmatt&Jz、const uint tId){
数据类型dW(0),stdDev(sqrt(dt));
正态分布维纳分布(0,stdDev);
//为的值创建数组
数据类型*JpmExpect=JpmArr[tId];
//执行Nrep重复实验
对于(uint r(0);r
我将其用作线性代数库,因此:

typedef Eigen::SparseMatrix<dtype, Eigen::RowMajor> ESpMatD;
typedef Eigen::Matrix<dtype, Eigen::Dynamic, Eigen::RowMajor> VectorXdrm;
typedef-Eigen::SparseMatrix-ESpMatD;
typedef特征::矩阵向量xdrm;
用作类型。上述辅助函数调用:

VectorXdrm& F1(const dtype a, const ESpMatD& A, const ESpMatD& B, const VectorXdrm& v) {
z.setZero(v.size());
y.setZero(v.size());

// z is for simplification
z = A*v;

//scalar intermediate value c = <v, Av>
dtype c = v.dot(z);

y = a * (2.0 * c * z - B * z - c * c * v);
return y;
}

VectorXdrm& F2(const dtype a, const ESpMatD& A, const VectorXdrm& v) {
//zero the data
z.setZero(v.size());
y.setZero(v.size());

z = A*v;

dtype c = v.dot(z);

y = sqrt(2.0 * a)*(z - c * v);
return y;
}
VectorXdrm&F1(常数数据类型a、常数ESpMatD&a、常数ESpMatD&B、常数矢量XDRM&v){
z、 设置零(v.size());
y、 设置零(v.size());
//z代表简化
z=A*v;
//标量中间值c=
D类型c=v点(z);
y=a*(2.0*c*z-B*z-c*c*v);
返回y;
}
矢量xDRM&F2(常数数据类型a、常数ESpMatD&a、常数矢量xDRM&v){
//将数据归零
z、 设置零(v.size());
y、 设置零(v.size());
z=A*v;
D类型c=v点(z);
y=sqrt(2.0*a)*(z-c*v);
返回y;
}
其中向量
z,y
属于
VectorXdrm
类型,并在同一文件中声明(模块全局)。 所有数组(
RNGarr、JpmArr、tmpPsiVecArr、tmpVecArr、psiVecArr
)都在main中初始化(通过使用
main.cpp
中的
extern
声明)。设置完成后,我使用
std::async
运行函数,等待所有操作完成,然后将
JpmArr
中的数据收集到
main()
中的单个数组中,并将其写入文件

问题: 如果我使用
std::launch::async
,结果是毫无意义的。 如果我使用
std::launch::deferred
计算结果和平均结果(只要数值方法允许)与我通过分析方法获得的结果相匹配

我再也不知道什么地方出了问题。我曾经在线性代数中使用Armadillo,但它是
normalize
例程交付的
nan
,因此我切换到了Eigen,它(在文档中)提示可以与多个线程一起使用-它仍然失败。 之前我没有使用过线程,现在我已经花了4天的时间试图让它工作并阅读了一些东西。后者引导我使用全局数组
RNGarr、JpmArr、tmpPsiVecArr、tmpvecar、psiVecArr
(在我尝试在
worker
中创建适当的数组并通过
struct workerResult
将结果传回main)以及使用
std::ref()
传递矩阵
Jplus、Jminus,Jz
添加到函数中。(为简洁起见,上面的函数中省略了最后一个)

但是我得到的结果仍然是错误的,我不知道什么是错误的,我应该怎么做才能得到正确的结果。
对于此类(线程)问题或参考的解决方案示例的任何输入和/或指针,我们将不胜感激。

停止使用globals。无论如何,这是一种糟糕的风格,在这里,多个线程将同时进行归零和变异
z
y


最简单的解决方法是在worker函数中用局部变量替换全局变量,这样每个对worker的并发调用都有自己的副本,并通过引用将它们传递到
F1
F2

每个线程中的计算之间显然存在一些交互,这可能是由于全局数据正在被调用由多个线程更新,或者尽管通过引用传递的某些结构在运行时发生了变化--
z
y
如果由多个线程更新,则它们不能是全局的--但可能还有许多其他问题

我建议你重构代码如下

  • 使其面向对象——定义一个自包含的类。获取提供给worker的所有参数,并使它们成为类的成员
  • 如果不确定数据结构是否正在变化,则不要通过引用传递它们。如果有疑问,假设最坏的情况并做出c