Search code examples
c++multithreadingeigen

Why does Eigen matrix calculations return zero when std::thread is used for multi threading?


I am trying to implement multi threading to distribute certain cpu intensive operations to different threads. However any Eigen declarations always returns zero when multi threading is used. Following is an example code that demonstrates this issue

#include "../Eigen/Core"
#include "../Eigen/LU"
#include "../Eigen/Sparse"
#include "../Eigen/StdVector"
#include <iostream>

#include <thread>
#include <mutex>

using namespace std;
using namespace Eigen;


void Multiply_3x3 (MatrixXd& matrix1, MatrixXd& matrix2, MatrixXd& results);

int main()
{

  MatrixXd a(3, 3);
  MatrixXd b(3, 3);
  MatrixXd c(3,3);

  a<<2,4,3,1,5,7,0,2,3;
  b<<2,4,3,1,5,7,0,2,3;
  
  //Multiply_3x3(a,b,c);
  std::thread thread_multi(Multiply_3x3, a, b, c);
  thread_multi.join();

  cout << " *** In Main Program ***" << endl;
  cout <<c(0,0)<<" , "<< c(0,1)<<" , "<< c(0,1)<<endl;
  cout<<c(1,0)<<" , "<<c(1,1)<<" , "<<c(1,1)<<endl;
  cout<<c(2,0)<<" , "<<c(2,1)<<" , "<<c(2,1)<<endl;


}

void Multiply_3x3 (MatrixXd& matrix1, MatrixXd& matrix2, MatrixXd& results)
{
  results = matrix1 * matrix2;

  cout << " *** In Multiply_3x3 ***" << endl;
  cout<<results(0,0)<<" , "<<results(0,1)<<" , "<<results(0,1)<<endl;
  cout<<results(1,0)<<" , "<<results(1,1)<<" , "<<results(1,1)<<endl;
  cout<<results(2,0)<<" , "<<results(2,1)<<" , "<<results(2,1)<<endl<<endl<<endl;  
}

The output from this run is

 *** In Multiply_3x3 ***
8 , 34 , 34
7 , 43 , 43
2 , 16 , 16


 *** In Main Program ***
1.69122e-306 , 1.95819e-306 , 1.95819e-306
9.34612e-307 , 6.23037e-307 , 6.23037e-307
9.34602e-307 , 6.2304e-307 , 6.2304e-307

As shown in the output the results are correct in the function Multiply_3x3. However the returned values are zero. If I don't use std:thread and call the function as shown in the commended section (//Multiply_3x3(a,b,c);) the results are correct in the calling function. Wondering if anyone could point out what I am missing here.


Solution

  • You have to apply std::ref to all matrices a, b and c when constructing thread. Without this, std::thread makes a copy passed arguments and operates on them, changing the copy of c matrix instead original c matrix defined in main.

      std::thread thread_multi(Multiply_3x3, std::ref(a), std::ref(b), std::ref(c));
      thread_multi.join();
    

    Demo


    Note, without std::ref your code doesn't compile on G++, it seems you are using Microsoft Visual which has some extensions (enabled by default) - for example, binding temporary object to lvalue reference. That is why your code was compiled. You can turn off this feature by adding /Za to compiler's flags.