8.4.2. TThreadedRun
In this case, the program starts using a single resource (the main thread), then it launches evaluation on dedicated threads (children), uses them and stops them before ending.
Threads use a shared memory paradigm: all threads have access to the same address space. All objects that are used are defined by the main thread. Evaluation threads only use (or duplicate) them. It’s only the main thread that follows the macro instructions, while its children only do the evaluation loop. Here is the interpretation of the inherited methods:
startSlavestarts some threads dedicated to evaluation (it is a unblocking operation), and then exits. These threads loops for evaluations.As we are on the master thread,
onMasteris true.stopSlaveputs fake items for evaluation. When the thread gets it, it stops their evaluation loop and exits. Main thread waits for all threads to be stopped.
TThreadedRun constructor has two arguments, a pointer to a TEval object and an integer. The
second argument is the number of threads that the user wants to use.
// Creating the threaded runner
TThreadedRun trun(&code,4);
One important thing to take care is that the user evaluation function need to be thread safe. For example, with the old ROOT5 interpreter, the rosenbrock macro (see Relauncher abstraction levels) cannot be distributed with thread. This is because the user function is interpreted and the Root interpreter is not thread safe. You have to turn it in a compiled format to make it works with threads.
Thread safe problems come usually with variable affectation. If two (or more) threads modify the same memory address at the same time, the code expected behaviour is usually disturbed. It can be a global or static variable, an embedded object working variable, a file descriptor, etc. Thread unsafe bug is difficult to squash. It may be necessary to clone objects to avoid such problems.
Warning
One might want to use TDataServer objects in code of TCJitEval instances that would be
distributed with a TThreadedRun object. In this case, it is mandatory to call the method
EnableThreadSafety() to remove all dataserver and tree from the internal ROOT register
which would induce race-condition. This can be done as below:
ROOT::EnableThreadSafety();
An example of this (very specific) usage, is shown in Macro “relauncherCJitFunctionThreadTest.C” for C++ mainly as it uses a CJit function which cannot be used in python.