--- myst: substitutions: sentence: python: "" cpp: | An example of this (very specific) usage, is shown in [](#use_cases_macro_relauncher_thread_test_cpp) for C++ mainly as it uses a CJit function which cannot be used in python. bloc1: python: 60,61 cpp: 72,73 bloc2: python: 53,54 cpp: "66" dedent: python: ":dedent:\n" cpp: "" --- (relauncher_trun_tthreadedrun)= # `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: - `startSlave` starts 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, `onMaster` is true. - `stopSlave` puts 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. {{ "```{literalinclude} " + parent_dir + "/roottest/uranie/doc/relauncher/teval_trun/" + language + "/teval_trun." + extension + "\n" + ":language: " + language + "\n" + ":lines: " + bloc1[language] + "\n" + dedent[language] + "```" }} 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" "}" + "\n" + "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:\n" + "\n" + "```{literalinclude} " + parent_dir + "/roottest/uranie/doc/relauncher/teval_trun/" + language + "/teval_trun." + extension + "\n" + ":language: " + language + "\n" + ":lines: " + bloc2[language] + "\n" + dedent[language] + "```\n" + "\n" + sentence[language] + "\n" + "````" }}