13.7.3. Macro “relauncherCJitFunctionThreadTest.C”
13.7.3.1. Objective
The goal of this macro is to show how to handle thread-safe compiled function (or code) that would
contain TDataServer objects (this is not particularly recommended, but has been requested to us).
This example is only written in C++ as the CJit interface only works for this, but the idea is the
same if one has a code and use the python interface. This will be further discussed below. The
function is pointless, a pure illustrative toy and the results is not important as long as one sees
that in one case, the macro runs smoothly while on the other hand, it crashes.
13.7.3.2. Macro
void multiply(double *x, double *y)
{
// New dataserver reading all points in flowrate
URANIE::DataServer::TDataServer test("test","notindir");
test.keepFinalTuple(false); // Remove the tuple from ROOT internal list
test.fileDataRead("flowrateUniformDesign.dat",false);
// Dummy functions with a loop to slow down the function
double max=-1000000;
for(int i=0; i<test.getNPatterns(); i++)
{
double val = test.getValue("ystar",i);
max = ((val>=max) ? val : max);
}
y[0] = max * x[0];
}
void relauncherCJitFunctionThreadTest(const int seed=0)
{
/* This macro can be used in two modes:
*/
bool threaded=true;
// If thread-safe, call this method that will take out the dataserver from ROOT internal list
if(threaded)
ROOT::EnableThreadSafety(); // part of the solution
// input and output attributes
URANIE::DataServer::TUniformDistribution x("multiplier",1,10);
URANIE::DataServer::TAttribute MultMean("MultMean");
// Interface to the compiled function above
URANIE::Relauncher::TCJitEval eval(multiply);
eval.addInput(&x);
eval.addOutput(&MultMean);
// Threaded runner
URANIE::Relauncher::TThreadedRun run(&eval,4);
run.startSlave();
if( run.onMaster() )
{
// Global dataserver
URANIE::DataServer::TDataServer tds("pouet","pouet_notindir");
tds.addAttribute(&x);
// Doe for the multiplier
URANIE::Sampler::TSampling sam(&tds,"lhs",24);
sam.generateSample();
// Run the code
URANIE::Relauncher::TLauncher2 launch(&tds, &run);
launch.solverLoop();
tds.getTuple()->SetScanField(-1);
tds.scan();
run.stopSlave();
}
}
The very first part of the macro is a function that would be applied to all points of our design-of-experiments.
The general context is simple: let’s assume one wants to find the maximum value of a variable in a
given dataset, and let’s assume that this maximum should have to be scaled by some factor. We create
the multiply function to do so, as done here:
void multiply(double *x, double *y)
{
// New dataserver reading all points in flowrate
URANIE::DataServer::TDataServer test("test","notindir");
test.keepFinalTuple(false); // Remove the tuple from ROOT internal list
test.fileDataRead("flowrateUniformDesign.dat",false);
// Dummy functions with a loop to slow down the function
double max=-1000000;
for(int i=0; i<test.getNPatterns(); i++)
{
double val = test.getValue("ystar",i);
max = ((val>=max) ? val : max);
}
y[0] = max * x[0];
}
In this function the dataset is always the same (flowrateUniformDesign.dat) and the multiplier is
the only input attribute. The maximum of the dataset is found by creating a TDataServer object, by
calling the fileDataRead method to read the dataset and by looping over the events (this is not at
all the best way to do it, but it is a toy model to show what problems can arise when a TDataServer
object is created in an evaluator use in multi-thread approach). Few important points in this
function to prevent from race condition (not thread-safe behaviour):
the
TDataServerobject is created statistically so that at the end of the function it is automatically destroyed;the line below is used to tell the
TDataServerobject not to write his data tree in the ROOT internal list and not to dump it in the archive file when the object is destroyedtest.keepFinalTuple(false); // Remove the tuple from ROOT internal list
the line below is used to tell the
fileDataReadmethod not to create the archive ROOT file once the dataset is read (thanks to the optional boolean set to false here)test.fileDataRead("flowrateUniformDesign.dat",false);
The main function starts then with a block that allows to test the main point here: the method develop by ROOT to prevent the internal list to store object which would lead to race conditions. This block is commented to explain how to run the use-case macro discuss here. The important part is, if one wants to run the macro properly, to call
ROOT::EnableThreadSafety(); // part of the solution
Once this is done, then the macro can be briefly described in the few key steps
create the input (multiplier) and output (MultMean) attribute;
create the interface to the
multiplyfunction;create the interface for the runner;
create the
TDataServerobject that would contain the multiplier and the results. This object is created within theonMaster()part because otherwise there would have been as many dataserver object as there are threads.create a sampler and a design-of-experiments to read 24 times the given dataset;
run the computations
At the end, once the macro is launched by using the command below, the
root -b -q relauncherCJitFunctionThreadTest.C
13.7.3.3. Console
--- Uranie v4.11/0 --- Developed with ROOT (6.36.06)
Copyright (C) 2013-2026 CEA/DES
Contact: support-uranie@cea.fr
Date: Thu Feb 12, 2026
************************************************
* Row * pouet__n_ * multiplie * MultMean. *
************************************************
* 0 * 1 * 8.1562084 * 1343.9800 *
* 1 * 3 * 6.5650956 * 1081.7964 *
* 2 * 0 * 4.1412811 * 682.40030 *
* 3 * 5 * 4.7243584 * 778.47978 *
* 4 * 2 * 9.4179988 * 1551.8978 *
* 5 * 4 * 7.0461633 * 1161.0667 *
* 6 * 7 * 7.4193739 * 1222.5644 *
* 7 * 6 * 2.5976785 * 428.04546 *
* 8 * 8 * 5.3607876 * 883.35059 *
* 9 * 9 * 5.6692661 * 934.18168 *
* 10 * 11 * 3.5864637 * 590.97748 *
* 11 * 10 * 1.0476136 * 172.62578 *
* 12 * 12 * 1.5680924 * 258.39027 *
* 13 * 13 * 4.8760831 * 803.48098 *
* 14 * 15 * 9.0195417 * 1486.2400 *
* 15 * 14 * 6.0024502 * 989.08374 *
* 16 * 16 * 9.9852106 * 1645.3630 *
* 17 * 18 * 2.4617970 * 405.65491 *
* 18 * 19 * 6.7059225 * 1105.0019 *
* 19 * 20 * 3.9170611 * 645.45333 *
* 20 * 17 * 3.1396825 * 517.35689 *
* 21 * 21 * 7.9536348 * 1310.5999 *
* 22 * 23 * 2.1125191 * 348.10091 *
* 23 * 22 * 8.6398795 * 1423.6793 *
************************************************