Hi @nicconflo, @ferhue,
Sure, here is the full reproducible with the example how to define several random engines 
Reproducible
Run it as root test.cpp.
I have tested it with ROOT 6.38
//test.cpp
struct RandomEngines{
RandomEngines(){
//Assuming you have <= 64 cores
for (int i=0; i<64; i++) engines.push_back( TRandom3( rd() ) );
}
std::vector< TRandom3 > engines;
// for random seeding of several random engines
std::random_device rd;
};
RandomEngines engines;
double GetRNG(unsigned int slot) { return engines.engines[slot].Gaus(); }
double GetRNG_single_engine() { return engines.engines[0].Gaus(); }
void test(){
auto* c1 = new TCanvas("c1", "c1", 1500, 500);
c1->Divide(3, 1);
ROOT::DisableImplicitMT();
auto df1 = ROOT::RDataFrame(10000000).Define("x", GetRNG_single_engine);
auto h1 = df1.Histo1D({"h1", "single core", 1000, -4, 4}, {"x"});
c1->cd(1);
h1->DrawClone();
ROOT::EnableImplicitMT(16);
auto df3 = ROOT::RDataFrame(10000000).Define("x", GetRNG_single_engine);
auto df4 = ROOT::RDataFrame(10000000).Define("x", GetRNG, {"rdfslot_"});
auto h3 = df3.Histo1D({"h3", "single random engine", 1000, -4, 4}, {"x"});
auto h4 = df4.Histo1D({"h4", "N random engines", 1000, -4, 4}, {"x"});
c1->cd(2);
h3->DrawClone();
c1->cd(3);
h4->DrawClone();
std::cout<<std::fixed<<std::setprecision(3)<<"Perfect : "<<"0.000"<<" +- "<<"1.000"<<std::endl;
std::cout<<std::fixed<<std::setprecision(3)<<"Single thread : "<<h1->GetMean()<<" +- "<<h1->GetStdDev()<<std::endl;
std::cout<<std::fixed<<std::setprecision(3)<<"Single random engine (MT): "<<h3->GetMean()<<" +- "<<h3->GetStdDev()<<std::endl;
std::cout<<std::fixed<<std::setprecision(3)<<"Several random engines (MT): "<<h4->GetMean()<<" +- "<<h4->GetStdDev()<<std::endl;
}
Output
Warning in <ROOT_TImplicitMT_DisableImplicitMT>: Implicit multi-threading is already disabled
Perfect : 0.000 +- 1.000
Single thread : -0.000 +- 0.999
Single random engine (MT): 0.001 +- 0.992
Several random engines (MT): -0.000 +- 0.999
You can see the weird spikes, but also, that the final STD is significantly off the value of the Gaus you’d expect.
You should also note that the documentation for TRandom3 actually suggests to use std::mt19937 as the random engine, because (some smart reasons).
Changing to std::mt19937 is rather easy. See below 
Reproducible with std::mt19937
//test.cpp
struct RandomEngines{
RandomEngines(){
//Assuming you have <= 64 cores
for (int i=0; i<64; i++) engines.push_back( std::mt19937( rd() ) );
}
std::vector< std::mt19937 > engines;
// for random seeding of several random engines
std::random_device rd;
};
RandomEngines engines;
std::normal_distribution<double> gaus(0., 1.);
double GetRNG(unsigned int slot) { return gaus(engines.engines[slot]); }
double GetRNG_single_engine() { return gaus(engines.engines[0]); }
void test(){
auto* c1 = new TCanvas("c1", "c1", 1500, 500);
c1->Divide(3, 1);
ROOT::DisableImplicitMT();
auto df1 = ROOT::RDataFrame(10000000).Define("x", GetRNG_single_engine);
auto h1 = df1.Histo1D({"h1", "single core", 1000, -4, 4}, {"x"});
c1->cd(1);
h1->DrawClone();
ROOT::EnableImplicitMT(16);
auto df3 = ROOT::RDataFrame(10000000).Define("x", GetRNG_single_engine);
auto df4 = ROOT::RDataFrame(10000000).Define("x", GetRNG, {"rdfslot_"});
auto h3 = df3.Histo1D({"h3", "single random engine", 1000, -4, 4}, {"x"});
auto h4 = df4.Histo1D({"h4", "N random engines", 1000, -4, 4}, {"x"});
c1->cd(2);
h3->DrawClone();
c1->cd(3);
h4->DrawClone();
std::cout<<std::fixed<<std::setprecision(3)<<"Perfect : "<<"0.000"<<" +- "<<"1.000"<<std::endl;
std::cout<<std::fixed<<std::setprecision(3)<<"Single thread : "<<h1->GetMean()<<" +- "<<h1->GetStdDev()<<std::endl;
std::cout<<std::fixed<<std::setprecision(3)<<"Single random engine (MT): "<<h3->GetMean()<<" +- "<<h3->GetStdDev()<<std::endl;
std::cout<<std::fixed<<std::setprecision(3)<<"Several random engines (MT): "<<h4->GetMean()<<" +- "<<h4->GetStdDev()<<std::endl;
}
Output of the reproducible with std::mt19937
Warning in <ROOT_TImplicitMT_DisableImplicitMT>: Implicit multi-threading is already disabled
Perfect : 0.000 +- 1.000
Single thread : 0.000 +- 1.000
Single random engine (MT): 0.001 +- 1.014
Several random engines (MT): -0.000 +- 0.999
What I find notably interesting, is that you don’t see any spikes with std::mt19937 even if using a single engine with MT enabled! So these spikes is somehow connected to using TRandom3 exactly.
Nevertheless, as you can see by standard deviations, it still produces wrong results! So you indeed need several random engine, for each thread.
I hope that helps 